Skip to content

feat(router): add introspection authentication bypass feature#2192

Merged
dkorittki merged 33 commits intomainfrom
dominik/eng-7980-allow-to-exclude-introspection-endpoint-from-auth
Oct 28, 2025
Merged

feat(router): add introspection authentication bypass feature#2192
dkorittki merged 33 commits intomainfrom
dominik/eng-7980-allow-to-exclude-introspection-endpoint-from-auth

Conversation

@dkorittki
Copy link
Copy Markdown
Contributor

@dkorittki dkorittki commented Sep 8, 2025

Summary by CodeRabbit

  • New Features

    • Configurable GraphQL introspection auth modes: require auth, allow skipping with a secret, or skip entirely; router emits warnings for mismatched introspection settings.
  • Configuration

    • New structured introspection settings (enabled + secret) and an ignore-introspection flag; legacy flag deprecated and schema enforces secret length.
  • Chores

    • Initialization moved to an options-driven API with explicit error handling and clearer introspection wiring.
  • Tests

    • Expanded coverage for introspection auth flows, GET/header/token variants, multi-provider JWTs, and config validation.

Checklist

Marked this PR as draft since I want to create a docs PR before this is here is ready for review.

Motivation and Context

This pull requests adds the ability to configure the router to bypass authentication, if the operation is identified as an introspection query. Optionally a separate, static secret for introspection can be configured, which has to be passed via Authorization header instead of the usual JWT token when an introspection query is sent.

The motivation behind this feature is that it allows users to configure GraphQL client tooling without the need to acquire valid auth tokens first, which sometimes is not easy in this scenario. It's meant to be used locally. This should not be enabled in production.

To enable this feature I added a new section to the router configuration called introspection:

introspection:
  enabled: true # deprecates the introspection_enabled config parameter
  skip_authentication: true # bypasses auth for introspection queries, if enabled (default: false)
  token: "demo" # optionally require a secret passed via Authorization header for introspection queries

Changes

  • Config parameter introspection_enabled is marked as deprecated
  • New config parameter introspection with three child parameters, as described above, added
  • AccessController is extended to know wether introspection auth bypass is enabled and what the secret is
  • AccessController provides a method to check wether the incoming operation is an introspection query (using a temporary OperationKit) and based on it's configuration, if it should be bypassed
  • PreHandler first checks via AccessController if authentication should be bypassed and skips it if true
  • Modified existing auth tests in router-tests to disable this feature for all existing tests (to reflect the default config)
  • Extended auth tests in router-tests to test authentication when this feature is enabled

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Sep 8, 2025

Walkthrough

Introduce structured introspection configuration and secret-based skip logic; convert AccessController to an options-based constructor returning (controller, error); add introspection-aware authentication paths in the GraphQL prehandler; update router wiring, config schema/fixtures, and many tests to use the new APIs.

Changes

Cohort / File(s) Summary of changes
Access controller core logic
router/core/access_controller.go
Add AccessControllerOptions (Authenticators, AuthenticationRequired, SkipIntrospectionQueries, IntrospectionSkipSecret); extend AccessController with introspection fields; change NewAccessController(opts)(*AccessController, error); add IntrospectionSecretConfigured() and IntrospectionAccess(r, body) with constant-time secret comparison.
GraphQL prehandler & auth flow
router/core/graphql_prehandler.go
Add per-request authenticationPass enum (None, Normal, IntrospectionSecret, Skip); centralize auth decision and failure handling; gate introspection vs non-introspection access; propagate auth state into operation handling and expression context.
Router wiring & config
router/core/router.go, router/core/router_config.go, router/core/supervisor_instance.go
Add introspectionConfig to router config; change WithIntrospection(enable)WithIntrospection(enable, config.IntrospectionConfiguration); supervisor builds AccessController from AccessControllerOptions with error handling and emits introspection-related warnings.
Config types & schema
router/pkg/config/config.go, router/pkg/config/config.schema.json
Add IntrospectionConfiguration (Enabled, Secret) and Authentication.IgnoreIntrospection; add Config.IntrospectionConfig; mark legacy IntrospectionEnabled as deprecated; extend JSON schema with introspection object, ignore_introspection, and secret validation.
Config fixtures & defaults
router/pkg/config/fixtures/full.yaml, router/pkg/config/testdata/config_defaults.json, router/pkg/config/testdata/config_full.json
Add introspection / IntrospectionConfig blocks and authentication.ignore_introspection; extend JWT JWKS entries with per-entry fields (refresh_interval, algorithms, refresh_unknown_kid); keep legacy introspection_enabled.
Config validation tests
router/pkg/config/config_test.go
Add TestValidateIntrospectionAuthConfig covering skip behavior, secret presence and min-length validation; strengthen file-mode parsing subtests.
Testenv & call-site updates for introspection
router-tests/testenv/testenv.go, router-tests/security_test.go
Update WithIntrospection call sites to pass config.IntrospectionConfiguration as second parameter (e.g., WithIntrospection(true, config.IntrospectionConfiguration{...})).
Tests — AccessController call-site updates
Multiple under router-tests/ (e.g., router-tests/authentication_test.go, router-tests/batch_test.go, router-tests/block_operations_test.go, router-tests/header_set_test.go, router-tests/modules/*, router-tests/prometheus_test.go, router-tests/ratelimit_test.go, router-tests/telemetry/*, router-tests/websocket_test.go, etc.)
Replace inline two-arg core.NewAccessController(...) usages with accessController, err := core.NewAccessController(core.AccessControllerOptions{...}); add require.NoError(t, err) and pass via core.WithAccessController(accessController); add introspection-focused tests/constants in authentication_test.go.
Misc test imports & formatting
router-tests/*
Minor import reorders and test harness adjustments to accommodate the new constructor signature, explicit error handling, and the centralized AccessController instance across tests.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "feat(router): add introspection authentication bypass feature" accurately describes the primary change being made in this changeset. The raw summary confirms that the PR introduces a new introspection authentication bypass capability through a new IntrospectionConfiguration struct with Enabled and Secret fields, an IgnoreIntrospection flag for authentication configuration, and enhancements to the AccessController to support introspection-specific authentication logic. The title is concise, clear, and specifically identifies the main feature addition without vague language or unnecessary detail.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e8f8a73 and ef28a46.

📒 Files selected for processing (8)
  • router-tests/testenv/testenv.go (1 hunks)
  • router-tests/websocket_test.go (10 hunks)
  • router/core/router.go (2 hunks)
  • router/core/supervisor_instance.go (2 hunks)
  • router/pkg/config/config.go (3 hunks)
  • router/pkg/config/config.schema.json (2 hunks)
  • router/pkg/config/testdata/config_defaults.json (2 hunks)
  • router/pkg/config/testdata/config_full.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • router/pkg/config/testdata/config_full.json
  • router-tests/testenv/testenv.go
  • router/pkg/config/testdata/config_defaults.json
  • router/core/router.go
  • router/pkg/config/config.go
  • router/pkg/config/config.schema.json
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-29T10:28:07.122Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/pkg/config/config.go:1028-1029
Timestamp: 2025-09-29T10:28:07.122Z
Learning: The deprecation strategy for IntrospectionEnabled field in router/pkg/config/config.go is to first mark it as deprecated, then migrate all call sites to use IntrospectionConfig.Enabled, and finally remove the deprecated field. The envDefault tag should be kept during the deprecation period for backward compatibility.

Applied to files:

  • router/core/supervisor_instance.go
📚 Learning: 2025-09-23T16:27:54.358Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/core/supervisor_instance.go:59-71
Timestamp: 2025-09-23T16:27:54.358Z
Learning: In the router codebase, AccessController creation follows a nil pattern where accessController == nil signals that no authentication should be performed. Other parts of the code (like the prehandler) check for accessController == nil to determine whether to skip authentication entirely. Always creating an AccessController would break this pattern and cause authentication to be attempted even when no authenticators are configured.

Applied to files:

  • router/core/supervisor_instance.go
🧬 Code graph analysis (2)
router/core/supervisor_instance.go (2)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (2)
  • WithAccessController (1819-1823)
  • WithIntrospection (1548-1553)
router-tests/websocket_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1819-1823)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: build-router
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: build_push_image
  • GitHub Check: integration_test (./events)
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: image_scan
  • GitHub Check: build_test
  • GitHub Check: build_test
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
router-tests/websocket_test.go (1)

139-145: LGTM! Consistent adoption of the new AccessController API across all test cases.

The migration to the options-based core.NewAccessController API is correctly and uniformly applied across all websocket tests. Each test properly:

  • Constructs the AccessController with explicit options
  • Checks for errors before proceeding
  • Passes the controller via WithAccessController
  • Keeps introspection bypass disabled (default behavior)

The consistent pattern ensures maintainability and aligns with the new API design.

Also applies to: 149-149, 196-202, 206-206, 252-258, 264-264, 318-324, 330-330, 383-389, 399-399, 452-458, 466-466, 508-514, 522-522, 916-922, 944-944

router/core/supervisor_instance.go (2)

61-72: LGTM! AccessController creation correctly implements the new API.

The migration to the options-based constructor is properly implemented:

  • Preserves the nil AccessController pattern (only created when authenticators exist)
  • Includes proper error handling
  • Correctly maps configuration fields to options

Based on learnings.


74-81: LGTM! Introspection configuration warnings are clear and accurate.

The warnings appropriately alert operators to configuration mismatches:

  • Missing secret when auth is bypassed (security concern)
  • Unused secret when auth bypass is disabled (configuration clarity)

Configuration paths use the correct dot notation.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the router label Sep 8, 2025
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Sep 8, 2025

Router image scan passed

✅ No security vulnerabilities found in image:

ghcr.io/wundergraph/cosmo/router:sha-70e3fbadba82dc7a7c2bbc01f0cdc6a348cf1f2f

@dkorittki
Copy link
Copy Markdown
Contributor Author

dkorittki commented Sep 8, 2025

fyi image scan fails because our distroless go image is vulnerable right now

GoogleContainerTools/distroless#1863

Will wait for upstream fix and then rerun CI step, should fetch the updated image automatically and then it should work.

EDIT: vulnerability fixed upstream.

The deprecation logic of enabling introspection
needed to be adjusted because it did not respect
disabling introspection when only the new config
parameter is used.

Now when either the deprecated or the new config
parameter disables introduction, it gets disabled
regardless if the deprecated value enables it.
The default value for introspection.enabled is true but
in router-tests due to the way config values are initiated,
the value was false, which broke tests. This commit changes
it by setting the value for introspection.enabled to it's
default value 'true'.
@dkorittki dkorittki marked this pull request as ready for review September 8, 2025 16:03
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (6)
router-tests/telemetry/telemetry_test.go (6)

9093-9094: Same as above for AccessController args and helper extraction.


9140-9141: Same as above for AccessController args and helper extraction.


9224-9225: Same as above for AccessController args and helper extraction.


9291-9292: Same as above for AccessController args and helper extraction.


9347-9348: Same as above for AccessController args and helper extraction.


9554-9555: Same as above for AccessController args and helper extraction.

🧹 Nitpick comments (18)
router/pkg/config/fixtures/full.yaml (1)

23-26: Clarify precedence with deprecated introspection_enabled

This fixture defines both the deprecated introspection_enabled and the new introspection.enabled. Please document or enforce precedence; ideally, drop the deprecated field from example fixtures to avoid confusion.

Optional cleanup (outside the changed hunk):

-introspection_enabled: true
router/core/router_config.go (1)

53-53: Expose new introspection settings in anonymized Usage() (without leaking the token)

Add two booleans to Usage: whether skip-auth is enabled and whether a token is configured (do not export the token value).

Apply this diff:

@@ func (c *Config) Usage() map[string]any {
-	usage["introspection"] = c.introspection
+	usage["introspection"] = c.introspection
+	usage["introspection_skip_authentication"] = c.introspectionConfig.SkipAuthentication
+	usage["introspection_token_set"] = c.introspectionConfig.Token != ""
router-tests/testenv/testenv.go (1)

1423-1425: Avoid mixing deprecated and new introspection APIs

Using both WithIntrospection(true) and WithIntrospectionConfig(...) invites drift. Prefer the new WithIntrospectionConfig in tests.

Apply this diff:

-		core.WithIntrospection(true),
-		core.WithIntrospectionConfig(config.IntrospectionConfiguration{
-			Enabled: true,
-		}),
+		core.WithIntrospectionConfig(config.IntrospectionConfiguration{
+			Enabled: true,
+		}),
router/pkg/config/testdata/config_full.json (1)

462-466: Document header semantics for the token

Please confirm in docs/schema whether the token must be sent as Authorization: Bearer <token> or as a raw value, and how it interacts with SkipAuthentication. Define precedence if both are set.

I can open a docs follow-up PR once confirmed.

router-tests/prometheus_test.go (1)

4131-4132: Reduce repetition of positional bool args with a test helper

To avoid future churn and improve readability across tests, consider a helper returning core.Option.

Apply this local replacement after adding the helper:

- core.WithAccessController(core.NewAccessController(authenticators, true, false, "")),
+ testenv.WithDefaultAccessController(authenticators, true),

Add to testenv (or a shared test helper):

package testenv

import (
  "github.com/wundergraph/cosmo/router/core"
  "github.com/wundergraph/cosmo/router/pkg/authentication"
)

func WithDefaultAccessController(authenticators []authentication.Authenticator, requireAuth bool) core.Option {
  return core.WithAccessController(core.NewAccessController(authenticators, requireAuth, false, ""))
}
router/core/router.go (2)

225-233: Make deprecation sync deterministic and avoid noisy warnings

Current logic logs a deprecation warning whenever the old flag is false, even if the new config wasn’t used and there’s no divergence. Also, the else-if branch silently rewrites the old flag without warning. Prefer: warn only when values diverge and make “false wins” explicit for safety.

-	// handle introspection config deprecation
-	// if either the old deprecated or the new config is set to false, introspection is disabled
-	if !r.introspection {
-		r.introspectionConfig.Enabled = r.introspection
-		r.logger.Warn("The introspection_enabled option is deprecated. Use the introspection.enabled option in the config instead.")
-	} else if !r.introspectionConfig.Enabled {
-		r.introspection = r.introspectionConfig.Enabled
-	}
+	// handle introspection config deprecation
+	// If values diverge, prefer safer behavior: false wins, and emit a single deprecation warning.
+	if r.introspection != r.introspectionConfig.Enabled {
+		if !r.introspection || !r.introspectionConfig.Enabled {
+			r.introspection = false
+			r.introspectionConfig.Enabled = false
+		}
+		r.logger.Warn("The introspection_enabled option is deprecated. Use introspection.enabled instead. Diverging values detected; 'false' takes precedence.")
+	}

1560-1565: Avoid shadowing the imported config package

Rename the parameter to align with nearby options and avoid overshadowing the config import.

-func WithIntrospectionConfig(config config.IntrospectionConfiguration) Option {
+func WithIntrospectionConfig(cfg config.IntrospectionConfiguration) Option {
 	return func(r *Router) {
-		r.introspectionConfig = config
+		r.introspectionConfig = cfg
 	}
 }
router-tests/websocket_test.go (1)

140-140: Signature updates look correct; consider a small helper and verify for stragglers

All call sites correctly pass the two new args (skip introspection auth, token). To reduce repetition/noise across tests, consider a tiny helper (e.g., newAccessController(authenticators, requireAuth bool)) that supplies the defaults false,"".

Run to ensure no remaining 2-arg constructor calls:

#!/bin/bash
# Find legacy usages of NewAccessController with exactly two arguments
rg -nP --type go '\bNewAccessController\s*\(\s*[^,()]+\s*,\s*[^,()]+\s*\)'

Also applies to: 189-189, 240-240, 299-299, 361-361, 421-421, 470-470, 886-886

router-tests/block_operations_test.go (1)

132-133: Updated constructor args are consistent with the new API

Looks good. Same optional helper suggestion as in other tests to avoid repeating false,"".

Also applies to: 286-287, 383-383

router-tests/telemetry/telemetry_test.go (1)

9044-9045: Confirm empty introspection token semantics; consider reducing repetition.

  • You pass NewAccessController(authenticators, false, false, ""). Please verify that an empty token ("") is treated as “no token configured” and cannot accidentally match an empty Authorization header value. Also confirm that skip-introspection-auth=false keeps auth enforced for introspection.

  • Minor: this 4-arg constructor appears multiple times. Consider a tiny helper to avoid call-site churn if the signature changes again.

Apply at call sites:

- core.WithAccessController(core.NewAccessController(authenticators, false, false, ""))
+ core.WithAccessController(newTestAccessController(authenticators))

Add once in this file (or testenv):

func newTestAccessController(authenticators core.Authenticators) core.AccessController {
	return core.NewAccessController(authenticators, false, false, "")
}
router/pkg/config/config.go (1)

986-991: Don’t serialize empty token values

Add omitempty so empty tokens aren’t emitted back to YAML or logs via config dumps.

 type IntrospectionConfiguration struct {
 	Enabled            bool   `yaml:"enabled" envDefault:"true" env:"INTROSPECTION_ENABLED"`
 	SkipAuthentication bool   `yaml:"skip_authentication" envDefault:"false" env:"INTROSPECTION_SKIP_AUTHENTICATION"`
-	Token              string `yaml:"token" env:"INTROSPECTION_TOKEN"`
+	Token              string `yaml:"token,omitempty" env:"INTROSPECTION_TOKEN"`
 }
router/core/supervisor_instance.go (2)

60-65: Enforce introspection token even without JWT authenticators

AccessController is only created when authenticators exist. If users configure only an introspection token (no JWT), it never gets enforced.

-	if len(authenticators) > 0 {
+	if len(authenticators) > 0 || cfg.IntrospectionConfig.SkipAuthentication || cfg.IntrospectionConfig.Token != "" {
 		options = append(options, WithAccessController(NewAccessController(
 			authenticators,
 			cfg.Authorization.RequireAuthentication,
 			cfg.IntrospectionConfig.SkipAuthentication,
 			cfg.IntrospectionConfig.Token,
 		)))
 	}

163-165: Use the new nested flag to control introspection

To avoid contradictory settings between deprecated and new flags, drive WithIntrospection from IntrospectionConfig.Enabled.

-		WithIntrospection(config.IntrospectionEnabled),
+		WithIntrospection(config.IntrospectionConfig.Enabled),
 		WithIntrospectionConfig(config.IntrospectionConfig),
router/core/access_controller.go (2)

20-24: Constructor grows boolean blindness; consider options struct.

Two trailing booleans make call‑sites error‑prone and reduce readability. Prefer a single options struct (or functional options) to carry authenticationRequired, skipIntrospectionAuth, and the token.

Also applies to: 26-33


100-112: Accept “Bearer ” form for the introspection token.

Current check requires the Authorization header to equal the raw token, which is surprising given normal usage. Allow both raw and “Bearer ” while keeping constant‑time compares.

Apply this diff:

 func (a *AccessController) isValidIntrospectionToken(r *http.Request) bool {
   // If no token is configured, allow introspection without authentication
   if len(a.introspectionAuthSkipToken) == 0 {
     return true
   }

   authHeader := r.Header.Get("Authorization")
   if authHeader == "" {
     return false
   }

-  return subtle.ConstantTimeCompare([]byte(authHeader), []byte(a.introspectionAuthSkipToken)) == 1
+  token := a.introspectionAuthSkipToken
+  // Accept exact token
+  if len(authHeader) == len(token) &&
+    subtle.ConstantTimeCompare([]byte(authHeader), []byte(token)) == 1 {
+    return true
+  }
+  // Accept "Bearer <token>"
+  bearer := "Bearer " + token
+  if len(authHeader) == len(bearer) &&
+    subtle.ConstantTimeCompare([]byte(authHeader), []byte(bearer)) == 1 {
+    return true
+  }
+  return false
 }
router-tests/authentication_test.go (3)

2509-2725: Great coverage; add a few hardening cases.

  • Mixed query (introspection + normal field) must not bypass auth.
  • GET /graphql with introspection in query param (if supported) should get the same treatment.
  • Authorization: "Bearer " should also bypass when a token is configured (post‑change in AccessController).

I can append subtests for these three scenarios; want a patch?


2621-2631: Secret scanner false positive; replace high‑entropy test token.

Gitleaks flags the literal token as a generic API key. Use a clearly fake, low‑entropy value and centralize it.

Apply this diff (and reuse in all places):

@@
-        token := "0aG3TVhkZ2lPy8ULUPQLXZ4JFPfpxk"
+        // Non‑secret, low‑entropy value to avoid triggering secret scanners.
+        token := "introspection-token-for-tests" // gitleaks:allow
@@
-            header := http.Header{
-                "Authorization": []string{token},
-            }
+            header := http.Header{
+                "Authorization": []string{token},
+            }

Optionally, lift the token to a file‑level const near the other test constants and reference it here and at Line 2649.


2550-2555: Assert JSON semantically to reduce brittle string compares.

For these response bodies, require.JSONEq improves robustness and readability.

-            require.Equal(t, simpleIntrospectionExpectedData, string(data))
+            require.JSONEq(t, simpleIntrospectionExpectedData, string(data))

Also applies to: 2580-2584, 2606-2611, 2634-2639

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a52c215 and 324bccd.

📒 Files selected for processing (22)
  • router-tests/authentication_test.go (68 hunks)
  • router-tests/batch_test.go (2 hunks)
  • router-tests/block_operations_test.go (3 hunks)
  • router-tests/header_set_test.go (1 hunks)
  • router-tests/modules/router_on_request_test.go (2 hunks)
  • router-tests/modules/set_authentication_scopes_test.go (3 hunks)
  • router-tests/modules/set_scopes_test.go (2 hunks)
  • router-tests/prometheus_test.go (1 hunks)
  • router-tests/ratelimit_test.go (1 hunks)
  • router-tests/telemetry/telemetry_test.go (7 hunks)
  • router-tests/testenv/testenv.go (1 hunks)
  • router-tests/websocket_test.go (8 hunks)
  • router/core/access_controller.go (3 hunks)
  • router/core/graphql_prehandler.go (1 hunks)
  • router/core/router.go (2 hunks)
  • router/core/router_config.go (1 hunks)
  • router/core/supervisor_instance.go (2 hunks)
  • router/pkg/config/config.go (2 hunks)
  • router/pkg/config/config.schema.json (1 hunks)
  • router/pkg/config/fixtures/full.yaml (1 hunks)
  • router/pkg/config/testdata/config_defaults.json (1 hunks)
  • router/pkg/config/testdata/config_full.json (1 hunks)
🧰 Additional context used
🪛 Gitleaks (8.27.2)
router/pkg/config/testdata/config_full.json

[high] 465-465: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

router-tests/authentication_test.go

[high] 2621-2621: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 2649-2649: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (17)
router/pkg/config/testdata/config_defaults.json (1)

231-235: Defaults look good; confirm precedence vs. deprecated flag

IntrospectionConfig.Enabled defaults to true and coexists with IntrospectionEnabled. Ensure one has clear precedence across loaders/options and tests.

Run to locate usages and confirm precedence in code:

#!/bin/bash
rg -n -C2 -S '\bIntrospectionEnabled\b|\bIntrospectionConfig\b'
router-tests/prometheus_test.go (1)

4131-4132: Aligns with new AccessController signature — looks good

Passing authenticationRequired=true with skipIntrospectionAuth=false and empty token preserves previous behavior while enabling the new API.

router-tests/batch_test.go (1)

340-341: Constructor updates match the expanded API

Using false for authenticationRequired and skipIntrospectionAuth with an empty token maintains existing test semantics while adopting the new signature.

Also applies to: 748-749

router-tests/header_set_test.go (1)

284-286: JWT-claim header test correctly requires authentication

Switch to the 4-arg constructor is accurate; requiring auth here is appropriate for claim extraction.

router-tests/modules/set_authentication_scopes_test.go (1)

37-39: AccessController calls updated consistently

All three sites now use the new constructor with defaults that preserve prior behavior for these scope-setting tests.

Also applies to: 78-80, 121-123

router-tests/modules/set_scopes_test.go (1)

66-68: New constructor usage is correct and consistent

Adopts the expanded signature without changing test intent.

Also applies to: 106-108

router-tests/ratelimit_test.go (1)

275-277: Auth-aware rate limit test updated appropriately

Injecting the AccessController via the new constructor is correct; keeping introspection bypass disabled matches the test’s purpose.

router-tests/modules/router_on_request_test.go (2)

8-10: Import aliasing LGTM

Alias improves clarity in this suite.


75-76: AccessController call updated correctly

Four-arg usage matches the new signature; no issues.

router/pkg/config/config.schema.json (2)

1363-1368: Deprecation handling for introspection_enabled looks consistent.

Defaults and deprecation messaging align with the new nested config and will minimize breakage.


1369-1390: ```shell
#!/bin/bash
set -eux

Find where the Introspection config struct is defined

rg -nP 'type\s+\wIntrospection\w\s+' --type go

Inspect usages of skip_authentication in code paths handling introspection

rg -n 'skip_authentication' -C3 --type go

Check how token is used in introspection/auth handlers

rg -n 'introspection' -C3 --type go
rg -n 'token' -C3 --type go


</blockquote></details>
<details>
<summary>router/core/supervisor_instance.go (1)</summary><blockquote>

`60-65`: **Constant‑time token comparison**

Ensure AccessController’s token check uses crypto/subtle.ConstantTimeCompare to avoid timing attacks.



```shell
#!/bin/bash
# Verify constant-time compare is used for introspection token checks
rg -n -C2 -g '!**/vendor/**' -S 'isValidIntrospectionToken|ConstantTimeCompare|subtle\.' --type=go
router/core/graphql_prehandler.go (1)

363-366: Gate bypass by “introspection enabled”

Confirm BypassAuthIfIntrospection returns false when introspection is disabled to avoid skipping auth for queries that will be blocked anyway.

router/core/access_controller.go (2)

4-4: Good choice: constant‑time compare for token.

Importing crypto/subtle avoids timing leaks on token checks.


53-96: Ensure bypass only for introspection‑only operations.

Please confirm OperationKit.isIntrospectionQuery returns true only when the operation contains exclusively introspection fields. If mixed queries (e.g., { __schema ... employees { id } }) also return true, this would create an auth bypass for normal data. Add a test that proves mixed queries do NOT bypass auth.

I can add a test variant to TestIntrospectionAuthentication that sends a mixed query and expects 401 when authentication is required. Want me to draft it?

router-tests/authentication_test.go (2)

46-47: Constructor call‑sites updated correctly.

All usages migrated to the 4‑arg NewAccessController; behavior preserved.

Also applies to: 67-68, 91-92, 117-118, 135-136, 160-161, 187-188, 213-214, 240-241, 271-272, 300-301, 325-326, 348-349, 375-376, 402-403, 431-432, 451-452, 471-472, 491-492, 516-517, 543-544, 570-571, 597-598, 654-655, 715-716, 736-737, 762-763, 815-816, 875-876, 918-919, 957-958, 1000-1001, 1219-1220, 1247-1248, 1368-1369, 1451-1452, 1473-1474, 1495-1496, 1521-1522, 1547-1548, 1582-1583, 1628-1629, 1657-1658, 1686-1687, 1715-1716, 1744-1745, 1773-1774, 1806-1807, 1835-1836, 1864-1865, 1897-1898, 1929-1930, 1960-1961, 1988-1989, 2019-2020, 2054-2055, 2110-2111, 2150-2151, 2194-2195, 2234-2235, 2283-2284, 2324-2325, 2368-2369, 2408-2409, 2450-2451, 2490-2491, 2519-2520


2649-2659: Repeat of the gitleaks issue above.

Use the same low‑entropy constant here to keep scanners green.

After the change, rerun the secret scan job to confirm the alert is gone.

Comment thread router/core/graphql_prehandler.go Outdated
Comment thread router/pkg/config/config.go Outdated
Comment thread router/pkg/config/fixtures/full.yaml Outdated
Comment thread router/pkg/config/testdata/config_full.json
Comment thread router/core/access_controller.go Outdated
The env var INTROSPECTION_ENABLED was used twice
to populate both, the new and deprecated config parameters.
This is solved by removing it from the deprecated config value.
There is deprecation logic in code active which will set the value
for both parameters.
Comment thread router/core/access_controller.go Outdated
Copy link
Copy Markdown
Contributor

@SkArchon SkArchon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good PR, main question related to GET request and parsing

Comment thread router/core/supervisor_instance.go Outdated
Copy link
Copy Markdown
Member

@endigma endigma left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some thoughts about duplicating/moving the operationkit, but here's some other things that should come first.

Comment thread router/pkg/config/config.go
Comment thread router/pkg/config/config.schema.json Outdated
Comment thread router/core/router.go
Instead of introspection.skip_authentication now provide
introspection.authentication_mode with 3 choices:
full = normal jwt auth for introspection queries
skip = skip auth for introspection queries
token = use static token for introspection queries
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (17)
router/core/router.go (1)

225-232: Strengthen deprecation handling and messaging when flags conflict

Currently you warn only when the legacy flag disables introspection; also warn when the new config disables it while the legacy flag is true, and standardize the path format to “/introspection/enabled”.

 // handle introspection config deprecation
 // if either the old deprecated or the new config is set to false, introspection is disabled
 if !r.introspection {
-   r.introspectionConfig.Enabled = r.introspection
-   r.logger.Warn("The introspection_enabled option is deprecated. Use the introspection.enabled option in the config instead.")
+   r.introspectionConfig.Enabled = r.introspection
+   r.logger.Warn("The legacy 'introspection_enabled' option is deprecated. Use '/introspection/enabled' instead.")
 } else if !r.introspectionConfig.Enabled {
-   r.introspection = r.introspectionConfig.Enabled
+   r.introspection = r.introspectionConfig.Enabled
+   r.logger.Warn("The legacy 'introspection_enabled' option is deprecated. '/introspection/enabled=false' overrides the legacy flag when they conflict.")
 }
router-tests/websocket_test.go (13)

195-195: Same WithAccessController wiring — OK

Matches the new API usage pattern.


241-242: OK to construct controller here as well

Pattern mirrors earlier block.


248-248: OK: controller passed via option

Consistent with prior change.


302-303: Controller ctor + error check — OK

No concerns.


309-309: WithAccessController usage — OK


362-363: Controller ctor with required=true — OK

Appropriate for “auth via initial payload” scenarios.


373-373: WithAccessController usage — OK


426-427: Controller ctor — OK


435-435: WithAccessController usage — OK


477-478: Controller ctor — OK


486-486: WithAccessController usage — OK


880-881: Controller ctor — OK


903-903: WithAccessController usage — OK

router/pkg/config/config.go (1)

1018-1020: Resolved env var collision on deprecated flag.
Removing env tag from IntrospectionEnabled prevents conflicts; nested config is now SoT.

router/core/graphql_prehandler.go (1)

358-389: Nice: no span leak—Authenticate span created only when used.
This addresses the earlier leak concern cleanly.

router/core/access_controller.go (1)

101-131: Support GET-based introspection detection.
Without this, ?query=… introspection over GET never bypasses auth.

-// isIntrospectionQuery checks if the operation in body is an introspection query.
-// It returns false if the operation is not an introspection query or we cannot parse it.
-func isIntrospectionQuery(operationProcessor *OperationProcessor, body []byte) bool {
-  if operationProcessor == nil || body == nil {
-    return false
-  }
-  operationKit, err := operationProcessor.NewKit()
-  if err != nil {
-    return false
-  }
-  defer operationKit.Free()
-  err = operationKit.UnmarshalOperationFromBody(body)
-  if err != nil {
-    return false
-  }
+// isIntrospectionRequest checks if the HTTP request is an introspection query (POST or GET).
+// It returns false if the operation is not introspection or cannot be parsed.
+func isIntrospectionRequest(r *http.Request, operationProcessor *OperationProcessor, body []byte) bool {
+  if operationProcessor == nil {
+    return false
+  }
+  operationKit, err := operationProcessor.NewKit()
+  if err != nil {
+    return false
+  }
+  defer operationKit.Free()
+  switch r.Method {
+  case http.MethodGet:
+    if err = operationKit.UnmarshalOperationFromURL(r.URL); err != nil {
+      return false
+    }
+  default:
+    if body == nil {
+      return false
+    }
+    if err = operationKit.UnmarshalOperationFromBody(body); err != nil {
+      return false
+    }
+  }
   err = operationKit.Parse()
   if err != nil {
     return false
   }
   isIntrospection, err := operationKit.isIntrospectionQuery()
   if err != nil {
     return false
   }
   return isIntrospection
 }
🧹 Nitpick comments (15)
router-tests/testenv/testenv.go (1)

1422-1424: API update LGTM (consider explicit auth mode for clarity)

Passing Enabled: true is fine; consider also setting AuthenticationMode: "full" to make the test resilient to future default changes.

- core.WithIntrospection(true, config.IntrospectionConfiguration{
-   Enabled: true,
- }),
+ core.WithIntrospection(true, config.IntrospectionConfiguration{
+   Enabled:            true,
+   AuthenticationMode: "full",
+ }),
router/core/router.go (1)

1554-1558: Avoid shadowing the imported config package

The parameter name “config” shadows the imported package; rename to cfg for clarity.

-func WithIntrospection(enable bool, config config.IntrospectionConfiguration) Option {
+func WithIntrospection(enable bool, cfg config.IntrospectionConfiguration) Option {
 	return func(r *Router) {
 		r.introspection = enable
-		r.introspectionConfig = config
+		r.introspectionConfig = cfg
 	}
 }
router-tests/prometheus_test.go (1)

4122-4124: Optional: DRY up AccessController setup across tests

Consider a tiny helper to reduce repetition.

// testutil/test_access.go
func NewTestAccessController(t *testing.T, auth []authentication.Authenticator, required bool) *core.AccessController {
	t.Helper()
	ac, err := core.NewAccessController(auth, required, core.IntrospectionAuthModeFull, "")
	require.NoError(t, err)
	return ac
}

Then replace local constructions with testutil.NewTestAccessController(t, authenticators, true).

Also applies to: 4134-4134

router-tests/header_set_test.go (1)

278-280: Optional: extract a shared helper for AccessController creation

Same helper as suggested in prometheus tests would keep these call sites concise.

Also applies to: 287-287

router-tests/ratelimit_test.go (1)

273-275: Optional: unify controller setup

Adopt the same small helper to create the controller (with required=false in this test) to keep tests consistent and terse.

Also applies to: 278-279

router-tests/websocket_test.go (1)

190-192: Reduce repetition: extract a tiny helper for AccessController setup

This exact pattern repeats throughout the file; a helper will shrink noise and ease future API tweaks.

Apply locally where used:

-		accessController, err := core.NewAccessController(authenticators, false, core.IntrospectionAuthModeFull, "")
-		require.NoError(t, err)
+		accessController := mustAccessController(t, authenticators, false)

Add once in this test file:

func mustAccessController(t *testing.T, authenticators []authentication.Authenticator, required bool) *core.AccessController {
	t.Helper()
	ac, err := core.NewAccessController(authenticators, required, core.IntrospectionAuthModeFull, "")
	require.NoError(t, err)
	return ac
}
router-tests/telemetry/telemetry_test.go (1)

9031-9033: DRY up repeated controller construction across subtests

The NewAccessController + require.NoError pattern is repeated in several subtests. Consider a tiny helper to reduce noise and make future signature changes easier.

Apply this local replacement in one spot as an example:

-	authenticators, authServer := integration.ConfigureAuth(t)
-	accessController, err := core.NewAccessController(authenticators, false, core.IntrospectionAuthModeFull, "")
-	require.NoError(t, err)
+	authenticators, authServer := integration.ConfigureAuth(t)
+	accessController := mustNewAccessController(t, authenticators)
...
-				RouterOptions: []core.Option{
-					core.WithAccessController(accessController),
-				},
+				RouterOptions: []core.Option{
+					core.WithAccessController(accessController),
+				},

Add this helper in the same file (or a shared test util):

// at file scope
// import "github.com/wundergraph/cosmo/router/pkg/authentication"

func mustNewAccessController(t *testing.T, authenticators []authentication.Authenticator) *core.AccessController {
	t.Helper()
	ac, err := core.NewAccessController(authenticators, false, core.IntrospectionAuthModeFull, "")
	require.NoError(t, err)
	return ac
}

Also applies to: 9047-9048

router/pkg/config/config.go (1)

986-990: Add type-safety and env-only validation for AuthenticationMode.
Consider using a typed alias matching core.IntrospectionAuthMode and validating env-only runs (when no YAML is loaded) to avoid invalid values slipping through.

Apply:

 type IntrospectionConfiguration struct {
   Enabled            bool   `yaml:"enabled" envDefault:"true" env:"INTROSPECTION_ENABLED"`
-  AuthenticationMode string `yaml:"authentication_mode" envDefault:"full" env:"INTROSPECTION_AUTHENTICATION_MODE"`
+  AuthenticationMode string `yaml:"authentication_mode" envDefault:"full" env:"INTROSPECTION_AUTHENTICATION_MODE"`
   Token              string `yaml:"token" env:"INTROSPECTION_TOKEN"`
 }

And after env.Parse in LoadConfig, validate:

 if err := env.Parse(&cfg.Config); err != nil {
   return nil, err
 }
+// Validate env-only introspection mode (schema validation won’t run without YAML)
+switch cfg.Config.IntrospectionConfig.AuthenticationMode {
+case "full", "token", "skip":
+default:
+  return nil, fmt.Errorf("invalid INTROSPECTION_AUTHENTICATION_MODE: %q (allowed: full|token|skip)", cfg.Config.IntrospectionConfig.AuthenticationMode)
+}
router/core/graphql_prehandler.go (1)

358-389: Expose an attribute when auth is bypassed for observability.
Helps tracing/metrics dashboards distinguish bypassed flows.

Apply:

-            if !skipAuth {
+            if !skipAuth {
               _, authenticateSpan := h.tracer.Start(r.Context(), "Authenticate",
                 trace.WithSpanKind(trace.SpanKindServer),
                 trace.WithAttributes(requestContext.telemetry.traceAttrs...),
               )
               …
             }
+            if skipAuth {
+              routerSpan.SetAttributes(attribute.Bool("wg.auth.bypassed", true))
+            }
router/pkg/config/config.schema.json (1)

1369-1400: Tighten schema docs and hide secret in tooling.
Add descriptions and mark token writeOnly; warn against production “skip”.

   "introspection": {
     "type": "object",
-    "description": "",
+    "description": "GraphQL introspection settings. For production, prefer 'full' or 'token'. Using 'skip' is not recommended.",
     "additionalProperties": false,
     "properties": {
       "enabled": {
         "type": "boolean",
-        "description": "",
+        "description": "Enable GraphQL introspection.",
         "default": true
       },
       "authentication_mode": {
         "type": "string",
         "enum": ["full", "token", "skip"],
-        "description": "Authentication mode for introspection queries. 'full' requires normal authentication, 'token' requires a specific introspection token, 'skip' bypasses authentication entirely.",
+        "description": "How to authenticate introspection queries. 'full' = require normal auth; 'token' = require a dedicated introspection token; 'skip' = no auth (not recommended for production).",
         "default": "full"
       },
       "token": {
         "type": "string",
-        "description": "Token to authenticate introspection requests. Required when introspection.authentication_mode is set to 'token', ignored otherwise.",
+        "description": "Static secret for introspection requests when authentication_mode = 'token'.",
+        "writeOnly": true,
         "minLength": 32
       }
     },
router/core/access_controller.go (1)

35-39: Name nit: introspectionAuthSkipToken reads oddly in “token” mode.
Consider renaming to introspectionAuthToken for clarity.

router-tests/authentication_test.go (4)

2818-2823: Test name/comment mismatch with behavior (ModeSkip ignores token)

You configure a token but run in IntrospectionAuthModeSkip where the token is intentionally ignored. Rename/comment to reflect that.

Apply:

-    t.Run("introspection query with auth skip and introspection token", func(t *testing.T) {
+    t.Run("introspection query with auth skip (token ignored)", func(t *testing.T) {
@@
-        // since we are skipping auth for introspection and have not configured
-        // a dedicated token for introspection queries, this query must succeed
+        // ModeSkip bypasses auth for introspection; any configured token is ignored.

2850-2857: Test name mismatch: not “auth skip”, this is token mode

This subtest uses IntrospectionAuthModeToken; rename for clarity.

-    t.Run("introspection query with auth skip and invalid introspection token", func(t *testing.T) {
+    t.Run("introspection query with token mode and invalid introspection token", func(t *testing.T) {

2701-2939: Add positive coverage for token mode and clarify header format

You cover ModeToken (negative) but not the happy path. Also, header format for the introspection token (raw vs "Bearer ") isn’t asserted.

  • Add a passing case for ModeToken:
+   t.Run("introspection query with token mode and valid introspection token", func(t *testing.T) {
+       t.Parallel()
+       authenticators, _ := ConfigureAuth(t)
+       token := "wg_test_introspection_token" // test-only token; gitleaks:allow
+       accessController, err := core.NewAccessController(authenticators, true, core.IntrospectionAuthModeToken, token)
+       require.NoError(t, err)
+       testenv.Run(t, &testenv.Config{
+           RouterOptions: []core.Option{core.WithAccessController(accessController)},
+       }, func(t *testing.T, xEnv *testenv.Environment) {
+           header := http.Header{"Authorization": []string{token}}
+           res, err := xEnv.MakeRequest(http.MethodPost, "/graphql", header, strings.NewReader(simpleIntrospectionQuery))
+           require.NoError(t, err)
+           defer res.Body.Close()
+           require.Equal(t, http.StatusOK, res.StatusCode)
+           require.Equal(t, "", res.Header.Get(xAuthenticatedByHeader))
+           data, _ := io.ReadAll(res.Body)
+           require.Equal(t, simpleIntrospectionExpectedData, string(data))
+       })
+   })
  • If ModeToken accepts a Bearer prefix as well, mirror the above with:
header := http.Header{"Authorization": []string{"Bearer " + token}}

Please confirm expected header semantics; if only raw is supported, we should document that invariant in the test name/comments.


2701-2939: Minor duplication: helper for AccessController setup

Consider a tiny local helper to cut the repeated NewAccessController boilerplate across subtests and reduce mistakes.

Example:

newAC := func(t *testing.T, authRequired bool, mode core.IntrospectionAuthMode, token string, auths ...authentication.Authenticator) *core.AccessController {
  ac, err := core.NewAccessController(auths, authRequired, mode, token)
  require.NoError(t, err)
  return ac
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ce05ec and 124cf0e.

📒 Files selected for processing (19)
  • router-tests/authentication_test.go (68 hunks)
  • router-tests/batch_test.go (2 hunks)
  • router-tests/block_operations_test.go (3 hunks)
  • router-tests/header_set_test.go (1 hunks)
  • router-tests/modules/router_on_request_test.go (2 hunks)
  • router-tests/modules/set_authentication_scopes_test.go (3 hunks)
  • router-tests/modules/set_scopes_test.go (2 hunks)
  • router-tests/prometheus_test.go (2 hunks)
  • router-tests/ratelimit_test.go (1 hunks)
  • router-tests/security_test.go (2 hunks)
  • router-tests/telemetry/telemetry_test.go (14 hunks)
  • router-tests/testenv/testenv.go (1 hunks)
  • router-tests/websocket_test.go (10 hunks)
  • router/core/access_controller.go (3 hunks)
  • router/core/graphql_prehandler.go (1 hunks)
  • router/core/router.go (2 hunks)
  • router/core/supervisor_instance.go (2 hunks)
  • router/pkg/config/config.go (2 hunks)
  • router/pkg/config/config.schema.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • router/core/supervisor_instance.go
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-21T15:06:36.664Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2067
File: router/pkg/config/config.schema.json:1637-1644
Timestamp: 2025-07-21T15:06:36.664Z
Learning: In the Cosmo router project, when extending JSON schema validation for security-sensitive fields like JWKS secrets, backwards compatibility is maintained by implementing warnings in the Go code rather than hard validation constraints in the schema. This allows existing configurations to continue working while alerting users to potential security issues.

Applied to files:

  • router/pkg/config/config.schema.json
📚 Learning: 2025-09-02T12:52:27.677Z
Learnt from: endigma
PR: wundergraph/cosmo#2181
File: router/core/operation_processor.go:0-0
Timestamp: 2025-09-02T12:52:27.677Z
Learning: Hash validation for persisted queries with query bodies is performed in router/core/graphql_prehandler.go in the handleOperation function, not in the APQ processing logic in operation_processor.go. This validates that extensions.persistedQuery.sha256Hash matches the query body before any APQ operations occur.

Applied to files:

  • router/core/access_controller.go
📚 Learning: 2025-09-02T12:52:27.677Z
Learnt from: endigma
PR: wundergraph/cosmo#2181
File: router/core/operation_processor.go:0-0
Timestamp: 2025-09-02T12:52:27.677Z
Learning: Hash validation for persisted queries with query bodies is performed in router/core/graphql_prehandler.go in the handleOperation function at lines 571-578, not in the APQ processing logic in operation_processor.go. This validates that extensions.persistedQuery.sha256Hash matches the computed query hash before any APQ operations occur. There's also a test case that verifies this behavior.

Applied to files:

  • router/core/access_controller.go
🧬 Code graph analysis (16)
router-tests/security_test.go (2)
router/core/router.go (1)
  • WithIntrospection (1554-1559)
router/pkg/config/config.go (1)
  • IntrospectionConfiguration (986-990)
router-tests/batch_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (43-58)
  • IntrospectionAuthModeFull (17-17)
router/core/router.go (3)
  • Option (172-172)
  • WithAccessController (1825-1829)
  • BatchingConfig (125-130)
router-tests/header_set_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (43-58)
  • IntrospectionAuthModeFull (17-17)
router/core/router.go (1)
  • WithAccessController (1825-1829)
router-tests/modules/set_authentication_scopes_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (43-58)
  • IntrospectionAuthModeFull (17-17)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router-tests/testenv/testenv.go (2)
router/core/router.go (1)
  • WithIntrospection (1554-1559)
router/pkg/config/config.go (1)
  • IntrospectionConfiguration (986-990)
router/core/access_controller.go (2)
router/pkg/authentication/authentication.go (1)
  • Authenticator (22-25)
router/core/operation_processor.go (1)
  • OperationProcessor (124-136)
router-tests/prometheus_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (43-58)
  • IntrospectionAuthModeFull (17-17)
router/core/router.go (1)
  • WithAccessController (1825-1829)
router-tests/modules/set_scopes_test.go (3)
router/core/access_controller.go (2)
  • NewAccessController (43-58)
  • IntrospectionAuthModeFull (17-17)
router/core/router_config.go (1)
  • Config (28-122)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router-tests/websocket_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (43-58)
  • IntrospectionAuthModeFull (17-17)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router-tests/block_operations_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (43-58)
  • IntrospectionAuthModeFull (17-17)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router-tests/authentication_test.go (3)
router/core/access_controller.go (4)
  • NewAccessController (43-58)
  • IntrospectionAuthModeFull (17-17)
  • IntrospectionAuthModeSkip (23-23)
  • IntrospectionAuthModeToken (20-20)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router-tests/utils.go (2)
  • ConfigureAuth (45-57)
  • JwksName (19-19)
router-tests/ratelimit_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (43-58)
  • IntrospectionAuthModeFull (17-17)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router-tests/modules/router_on_request_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (43-58)
  • IntrospectionAuthModeFull (17-17)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router-tests/telemetry/telemetry_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (43-58)
  • IntrospectionAuthModeFull (17-17)
router/core/router.go (1)
  • WithAccessController (1825-1829)
router/core/router.go (1)
router/pkg/config/config.go (1)
  • IntrospectionConfiguration (986-990)
router/core/graphql_prehandler.go (2)
router/internal/expr/expr.go (3)
  • Context (35-39)
  • Request (66-75)
  • LoadAuth (183-195)
router/pkg/trace/utils.go (1)
  • AttachErrToSpan (75-81)
🪛 Gitleaks (8.27.2)
router-tests/authentication_test.go

[high] 2825-2825: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 2855-2855: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: build-router
  • GitHub Check: build_test
  • GitHub Check: build_push_image
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: build_test
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
  • GitHub Check: integration_test (./events)
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: image_scan
🔇 Additional comments (29)
router-tests/security_test.go (1)

344-346: API update LGTM

Updated to WithIntrospection(false, config.IntrospectionConfiguration{Enabled: false}) matches the new signature and intent.

router-tests/batch_test.go (2)

336-343: AccessController construction updated correctly

Using the new 4-arg constructor with error handling is correct; passing IntrospectionAuthModeFull and empty token matches prior behavior.


743-754: AccessController wiring LGTM

Creating once and injecting via WithAccessController keeps tests clean and mirrors the new API.

router-tests/modules/set_authentication_scopes_test.go (6)

35-41: AccessController construction updated correctly

New signature used with require.NoError; good.


39-43: Controller injection LGTM

Passing the pre-built controller via RouterOptions is consistent across tests.


79-85: AccessController construction updated correctly

Consistent usage with IntrospectionAuthModeFull and empty token.


84-84: Controller injection LGTM

Matches updated API.


125-127: AccessController construction updated correctly

Good to see error handling added.


130-130: Controller injection LGTM

Consistent with the rest of the suite.

router/core/router.go (1)

1554-1558: No remaining single-arg WithIntrospection calls — all call sites now use the new two-arg signature.

router-tests/modules/set_scopes_test.go (2)

64-70: AccessController construction and injection LGTM

Matches the new API and keeps previous behavior.


107-113: Second occurrence LGTM

Consistent and correct.

router-tests/prometheus_test.go (1)

4122-4124: LGTM: explicit AccessController with full introspection auth preserves previous semantics

Constructor args look right and the error is handled; wiring via WithAccessController is correct for claims-based metric extraction.

Also applies to: 4134-4134

router-tests/header_set_test.go (1)

278-280: LGTM: switched to new AccessController API with explicit mode

Using IntrospectionAuthModeFull and passing the controller via RouterOptions is correct for the auth-claim header rule test.

Also applies to: 287-287

router-tests/ratelimit_test.go (1)

273-275: LGTM: optional auth fits the claim-derived rate-limit key test

authenticationRequired=false is appropriate here to allow claim extraction without enforcing auth; controller is correctly injected.

Also applies to: 278-279

router-tests/websocket_test.go (2)

138-140: Explicit AccessController construction + error handling — OK

Using IntrospectionAuthModeFull with an empty token preserves previous WS auth semantics; error is properly asserted.


143-143: Pass pre-built controller via WithAccessController — OK

Separating construction from wiring improves clarity and makes failures visible.

router-tests/telemetry/telemetry_test.go (2)

9031-9033: LGTM: tests correctly adopt the new AccessController API and inject it via WithAccessController

  • Constructing the controller with the new 4-arg signature and asserting require.NoError is correct.
  • Passing the pointer into core.WithAccessController matches the updated Option contract.
  • Using IntrospectionAuthModeFull maintains prior behavior for these telemetry tests.

Also applies to: 9047-9048, 9084-9086, 9099-9100, 9135-9137, 9149-9150, 9211-9213, 9236-9237, 9289-9291, 9306-9306, 9351-9352, 9365-9366, 9554-9556, 9574-9575


9031-9033: All NewAccessController calls updated to 4-arg constructor
No 2- or 3-argument usages remain.

router-tests/modules/router_on_request_test.go (2)

8-10: LGTM: import aliasing looks fine.


73-79: Correct migration to new AccessController API.
Constructor + error handling + WithAccessController usage are all correct.

router-tests/block_operations_test.go (3)

130-136: Good: centralized AccessController creation + error handling.


286-292: Good: migrated to injected access controller.


381-390: Good: consistent wiring across tests.

router/pkg/config/config.schema.json (1)

1363-1368: Deprecation entry looks correct.
Clear message and default preserved.

router/core/access_controller.go (2)

12-24: Enum definition is clear and future-proof.


41-58: Constructor validation is correct.
Erroring on invalid mode prevents misconfig at startup.

router-tests/authentication_test.go (2)

27-34: Good addition: minimal introspection fixtures

The simple query/expected payload keeps tests fast and readable.


42-49: LGTM: explicit AccessController injection

Migrating tests to core.WithAccessController(accessController) is clean and aligns with the new constructor API.

Comment thread router-tests/authentication_test.go Outdated
Comment thread router/core/access_controller.go
Comment thread router/core/access_controller.go Outdated
Comment thread router/core/access_controller.go Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
router/pkg/config/config_test.go (3)

1297-1371: Add happy-path for authentication_mode: skip

Include a positive test to lock in acceptance of skip mode.

Apply this diff near the end of TestValidateIntrospectionAuthConfig:

@@
 	t.Run("token too short", func(t *testing.T) {
 		t.Parallel()
@@
 		require.ErrorContains(t, err, "at '/introspection/token': minLength: got 15, want 32")
 	})
+
+	t.Run("valid config with skip mode", func(t *testing.T) {
+		t.Parallel()
+
+		f := createTempFileFromFixture(t, `
+version: "1"
+
+introspection:
+  enabled: true
+  authentication_mode: skip
+`)
+		_, err := LoadConfig([]string{f})
+		require.NoError(t, err)
+	})

1297-1371: Add boundary test for token length = 32

Prevents regressions on minLength enforcement.

Apply this diff:

@@
 	t.Run("valid config with token", func(t *testing.T) {
 		t.Parallel()
@@
 		require.NoError(t, err)
 	})
 
+	t.Run("valid token with exact 32 chars", func(t *testing.T) {
+		t.Parallel()
+		// 32 'a' characters
+		f := createTempFileFromFixture(t, `
+version: "1"
+
+introspection:
+  enabled: true
+  authentication_mode: token
+  token: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+`)
+		_, err := LoadConfig([]string{f})
+		require.NoError(t, err)
+	})

1297-1371: Optional: DRY up YAML fixture generation

A tiny helper reduces duplication and makes future cases cheaper to add.

I can push a helper like:

func introspectionYAML(enabled bool, mode, token string) string {
	tok := ""
	if token != "" {
		tok = fmt.Sprintf("\n  token: %s", token)
	}
	return fmt.Sprintf(`
version: "1"

introspection:
  enabled: %t
  authentication_mode: %s%s
`, enabled, mode, tok)
}

Then subtests can pass createTempFileFromFixture(t, introspectionYAML(true, "token", strings.Repeat("a", 32))).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 124cf0e and 8bc3f46.

📒 Files selected for processing (4)
  • router/pkg/config/config_test.go (1 hunks)
  • router/pkg/config/fixtures/full.yaml (1 hunks)
  • router/pkg/config/testdata/config_defaults.json (1 hunks)
  • router/pkg/config/testdata/config_full.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • router/pkg/config/fixtures/full.yaml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-21T14:46:34.879Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2067
File: router/pkg/authentication/jwks_token_decoder.go:80-106
Timestamp: 2025-07-21T14:46:34.879Z
Learning: In the Cosmo router project, required field validation for JWKS configuration (Secret, Algorithm, KeyId) is handled at the JSON schema level in config.schema.json rather than through runtime validation in the Go code at router/pkg/authentication/jwks_token_decoder.go.

Applied to files:

  • router/pkg/config/testdata/config_defaults.json
🧬 Code graph analysis (1)
router/pkg/config/config_test.go (1)
router/pkg/config/config.go (1)
  • LoadConfig (1098-1210)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: build-router
  • GitHub Check: build_test
  • GitHub Check: image_scan
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: build_push_image
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: integration_test (./events)
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
router/pkg/config/testdata/config_full.json (2)

462-466: IntrospectionConfig snapshot looks correct; placeholder token avoids secret scanners

AuthenticationMode: "full" with a ≥32-char placeholder token is fine and aligns with schema; thanks for removing the high-entropy token.


462-466: Docs/PR text: align on “authentication_mode” vs “skip_authentication”

PR summary mentions skip_authentication, but the config uses authentication_mode ("full" | "token" | "skip"). Ensure the docs PR reflects the final shape and header expectations for token mode.

router/pkg/config/testdata/config_defaults.json (1)

231-235: Defaults fixture matches new schema

Enabled: true with AuthenticationMode: "full" and empty token is a sensible default. No changes requested.

router/pkg/config/config_test.go (1)

1297-1371: Good coverage of introspection auth schema paths

Covers happy paths (full, token) and key failures (invalid mode, missing token, minLength). Looks solid.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
router-tests/authentication_test.go (1)

42-49: Optional: factor a tiny helper to reduce repetition

AccessControllerOptions blocks repeat across many tests. Consider a small helper (in test utils) to build the controller to DRY this up.

Also applies to: 71-79, 103-111, 138-145, 164-171, 197-204, 232-239, 266-273, 300-308, 340-347, 376-384, 410-417, 441-448, 511-518, 631-639, 665-672, 700-707, 735-742, 770-777, 831-838, 905-911, 933-940, 965-972, 1028-1035, 1095-1101, 1146-1152, 1193-1199, 1241-1247, 1335-1341, 1641-1647, 1731-1737, 1761-1767, 1791-1797, 1826-1832, 1860-1866, 1949-1955, 1986-1992, 2023-2029, 2060-2065, 2097-2103, 2134-2139, 2175-2181, 2212-2217, 2249-2254, 2290-2295, 2331-2336, 2368-2373, 2405-2410, 2444-2450, 2486-2492, 2551-2556, 2599-2605, 2651-2656, 2695-2701, 2756-2761, 2801-2806, 2856-2862, 2901-2906, 2954-2961, 3002-3008

router/core/supervisor_instance.go (2)

73-80: Gate warnings when auth is configured; avoid misleading logs

If there are no authenticators, these warnings can confuse (no auth is enforced at all). Guard them by checking authenticators present.

Apply:

- if cfg.Authentication.IgnoreIntrospection && cfg.IntrospectionConfig.Secret == "" {
+ if len(authenticators) > 0 && cfg.Authentication.IgnoreIntrospection && cfg.IntrospectionConfig.Secret == "" {
   params.Logger.Warn("introspection operations are not authenticated. " +
     "Consider setting /introspection/secret or set /authentication/ignore_introspection to false. Do not use this in production.")
 }
- if !cfg.Authentication.IgnoreIntrospection && cfg.IntrospectionConfig.Secret != "" {
+ if len(authenticators) > 0 && !cfg.Authentication.IgnoreIntrospection && cfg.IntrospectionConfig.Secret != "" {
   params.Logger.Warn("/introspection/secret is ignored because /authentication/ignore_introspection is false.")
 }

171-179: Prefer the new nested flag as source of truth

Pass IntrospectionConfig.Enabled to WithIntrospection to avoid ambiguity with the deprecated boolean.

Apply:

-        WithIntrospection(config.IntrospectionEnabled, config.IntrospectionConfig),
+        WithIntrospection(config.IntrospectionConfig.Enabled, config.IntrospectionConfig),
router/core/access_controller.go (2)

35-37: Fix stale constructor comment (no invalid “auth mode”).

The comment mentions an introspection auth mode that no longer exists and suggests non-nil errors that aren’t produced.

Apply:

-// NewAccessController creates a new AccessController.
-// It returns an error if the introspection auth mode is invalid.
+// NewAccessController creates a new AccessController.
+// Note: currently returns a nil error; the error return is reserved for future configuration validation.

71-71: Rename unused param to underscore.

Communicates intent and appeases linters without API break.

Apply:

-func (a *AccessController) IntrospectionAccess(r *http.Request, body []byte) bool {
+func (a *AccessController) IntrospectionAccess(r *http.Request, _ []byte) bool {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f8c577 and 2d3c46a.

📒 Files selected for processing (21)
  • router-tests/authentication_test.go (68 hunks)
  • router-tests/batch_test.go (2 hunks)
  • router-tests/block_operations_test.go (3 hunks)
  • router-tests/header_set_test.go (1 hunks)
  • router-tests/modules/router_on_request_test.go (2 hunks)
  • router-tests/modules/set_authentication_scopes_test.go (3 hunks)
  • router-tests/modules/set_scopes_test.go (2 hunks)
  • router-tests/prometheus_test.go (2 hunks)
  • router-tests/ratelimit_test.go (1 hunks)
  • router-tests/telemetry/telemetry_test.go (14 hunks)
  • router-tests/websocket_test.go (10 hunks)
  • router/core/access_controller.go (3 hunks)
  • router/core/graphql_prehandler.go (7 hunks)
  • router/core/router.go (2 hunks)
  • router/core/supervisor_instance.go (2 hunks)
  • router/pkg/config/config.go (3 hunks)
  • router/pkg/config/config.schema.json (2 hunks)
  • router/pkg/config/config_test.go (1 hunks)
  • router/pkg/config/fixtures/full.yaml (2 hunks)
  • router/pkg/config/testdata/config_defaults.json (2 hunks)
  • router/pkg/config/testdata/config_full.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
  • router/pkg/config/testdata/config_defaults.json
  • router/pkg/config/config.schema.json
  • router-tests/websocket_test.go
  • router-tests/block_operations_test.go
  • router-tests/telemetry/telemetry_test.go
  • router-tests/modules/set_scopes_test.go
  • router/pkg/config/testdata/config_full.json
  • router/pkg/config/config_test.go
  • router/pkg/config/fixtures/full.yaml
  • router-tests/batch_test.go
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2025-09-02T12:52:27.677Z
Learnt from: endigma
PR: wundergraph/cosmo#2181
File: router/core/operation_processor.go:0-0
Timestamp: 2025-09-02T12:52:27.677Z
Learning: Hash validation for persisted queries with query bodies is performed in router/core/graphql_prehandler.go in the handleOperation function, not in the APQ processing logic in operation_processor.go. This validates that extensions.persistedQuery.sha256Hash matches the query body before any APQ operations occur.

Applied to files:

  • router/core/access_controller.go
📚 Learning: 2025-09-02T12:52:27.677Z
Learnt from: endigma
PR: wundergraph/cosmo#2181
File: router/core/operation_processor.go:0-0
Timestamp: 2025-09-02T12:52:27.677Z
Learning: Hash validation for persisted queries with query bodies is performed in router/core/graphql_prehandler.go in the handleOperation function at lines 571-578, not in the APQ processing logic in operation_processor.go. This validates that extensions.persistedQuery.sha256Hash matches the computed query hash before any APQ operations occur. There's also a test case that verifies this behavior.

Applied to files:

  • router/core/access_controller.go
📚 Learning: 2025-09-10T12:33:59.146Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/core/access_controller.go:3-10
Timestamp: 2025-09-10T12:33:59.146Z
Learning: For introspection token authentication in the router, the Authorization header should contain the exact static secret as configured, without Bearer prefix or whitespace normalization. Any deviation should be treated as invalid authentication.

Applied to files:

  • router/core/access_controller.go
📚 Learning: 2025-09-22T11:13:39.415Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/keyfunc/keyfunc_test.go:167-178
Timestamp: 2025-09-22T11:13:39.415Z
Learning: When reviewing forked code from external libraries, gitleaks warnings for hardcoded test tokens/credentials should typically be ignored as they are legitimate test fixtures from the upstream source, not real sensitive data.

Applied to files:

  • router-tests/authentication_test.go
📚 Learning: 2025-09-17T18:13:31.021Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/jwks_token_decoder.go:176-199
Timestamp: 2025-09-17T18:13:31.021Z
Learning: In router/pkg/authentication/jwks_token_decoder.go, when AllowEmptyAlgorithm is true, the allowedAlgorithms slice is populated by getSupportedAlgorithms() from validation_store.go, ensuring it's never empty and preventing unintended token rejections. The validation store maintains its own internal supported algorithms map that gets returned regardless of input parameters.

Applied to files:

  • router-tests/authentication_test.go
📚 Learning: 2025-09-17T18:13:31.021Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/jwks_token_decoder.go:176-199
Timestamp: 2025-09-17T18:13:31.021Z
Learning: In router/pkg/authentication/jwks_token_decoder.go, when AllowEmptyAlgorithm is true, the allowedAlgorithms slice is populated by getSupportedAlgorithms() from validation_store.go, ensuring it's never empty and preventing unintended token rejections.

Applied to files:

  • router-tests/authentication_test.go
🧬 Code graph analysis (11)
router-tests/modules/set_authentication_scopes_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router/core/supervisor_instance.go (2)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (2)
  • WithAccessController (1825-1829)
  • WithIntrospection (1554-1559)
router/pkg/config/config.go (1)
demo/pkg/subgraphs/test1/subgraph/model/models_gen.go (1)
  • Secret (667-669)
router-tests/ratelimit_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router-tests/modules/router_on_request_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router-tests/prometheus_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (1)
  • WithAccessController (1825-1829)
router-tests/header_set_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (1)
  • WithAccessController (1825-1829)
router/core/access_controller.go (1)
router/pkg/authentication/authentication.go (1)
  • Authenticator (22-25)
router/core/router.go (1)
router/pkg/config/config.go (1)
  • IntrospectionConfiguration (988-991)
router-tests/authentication_test.go (4)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router-tests/testenv/testenv.go (3)
  • Run (107-124)
  • Config (286-342)
  • Environment (1731-1767)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router-tests/utils.go (2)
  • ConfigureAuth (45-57)
  • JwksName (19-19)
router/core/graphql_prehandler.go (2)
router/internal/expr/expr.go (3)
  • Request (66-75)
  • LoadAuth (183-195)
  • Context (35-39)
router/pkg/trace/utils.go (1)
  • AttachErrToSpan (75-81)
🔇 Additional comments (22)
router-tests/modules/set_authentication_scopes_test.go (3)

35-41: LGTM! Consistent migration to new AccessController API.

The changes correctly migrate to the new core.AccessControllerOptions struct pattern, following the same pattern used across the test suite. All required parameters are explicitly set for clarity.


84-90: LGTM! Consistent API usage.


135-141: LGTM! Maintains consistency across all test cases.

router/core/router.go (4)

214-219: Ensure consistent deprecation message format.

The deprecation messages use different path formats. Consider standardizing to be consistent with the introspection deprecation message format.

#!/bin/bash
# Check for all deprecation message formats in the codebase
rg -n "option is deprecated.*Use the.*option" --type go

225-233: LGTM! Well-handled deprecation and synchronization logic.

The introspection configuration deprecation is handled correctly with proper backward compatibility:

  1. Logs a deprecation warning when the old option is used
  2. Synchronizes the configuration between old and new fields
  3. Ensures either option can disable introspection

1554-1558: LGTM! Correct API update for WithIntrospection.

The function signature is properly updated to accept the new introspection configuration structure.


1825-1828: LGTM! Clean implementation of WithAccessController.

The option correctly accepts a pre-created AccessController instance.

router-tests/prometheus_test.go (1)

4122-4129: LGTM! Correct migration to new AccessController API.

The test properly creates an AccessController with the new options pattern and includes error handling as required.

router-tests/header_set_test.go (1)

278-285: LGTM! Proper migration to new AccessController API.

The test correctly uses the new AccessControllerOptions struct and handles the error return value.

router-tests/ratelimit_test.go (1)

273-284: LGTM: AccessControllerOptions usage and injection

The migration to options-based AccessController and injecting it via WithAccessController is correct and consistent with the new API.

Also applies to: 283-283

router-tests/authentication_test.go (2)

3193-3211: Clarify header scheme for introspection secret (optional docs note)

Tests use Authorization: (no scheme). Ensure docs clearly state the expected header format to avoid confusion with bearer tokens.


3031-3321: Introspection auth-bypass test coverage — LGTM; verify constructor usage

Found multiple NewAccessController references (router/core/access_controller.go:37, router/core/supervisor_instance.go:60, numerous router-tests/*). Confirm these are intended or update them.

router-tests/modules/router_on_request_test.go (1)

8-10: LGTM: import alias and controller wiring

Alias import is fine; controller construction and injection align with the new API.

Also applies to: 73-80, 83-86

router/core/supervisor_instance.go (1)

59-71: LGTM: build AccessController from authenticators

Construction via AccessControllerOptions and injection is correct.

router/core/graphql_prehandler.go (4)

107-116: Auth-pass tracking for introspection — LGTM

The authenticationPass enum and propagation through httpOperation is clear and keeps downstream checks simple.

Also applies to: 118-126


367-407: Auth flow handling — LGTM

Span lifecycle is correct; success and failure paths end the span, and auth context is only populated on success.


680-709: Authorization gate respects introspection modes — LGTM

Non-introspection requires normal auth; introspection allows normal, secret, or skip. Matches tests and the feature design.


1145-1157: Good centralization of auth failure response

Shared helper keeps logging, spans, and HTTP response consistent.

router/pkg/config/config.go (1)

496-499: Verify JSON schema documents new introspection fields and deprecation

rg search returned no matches in router/pkg/config — cannot confirm schema changes; ensure the JSON schema documents IntrospectionConfiguration (with env mappings), Authentication.ignore_introspection, and a deprecation notice for introspection_enabled (and INTROSPECTION_SECRET env if applicable).

router/core/access_controller.go (3)

19-25: Good move to Options struct.

Constructor ergonomics improved; fields are clear.


29-32: Controller fields align with options.

No concerns.


64-67: Helper reads well.

Clear signal for downstream checks.

Comment thread router/core/access_controller.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (6)
router/pkg/config/fixtures/full.yaml (1)

23-25: Introspection block looks good; add an inline hint to reduce confusion

Secret is only honored when authentication.ignore_introspection is true. Add a short comment to make that clear in the fixture.

 introspection:
   enabled: true
-  secret: 'AN_EXAMPLE_PLACEHOLDER_SECRET_ONLY'
+  secret: 'AN_EXAMPLE_PLACEHOLDER_SECRET_ONLY'
+  # Note: secret is only used when authentication.ignore_introspection is true
router/pkg/config/config.schema.json (2)

1369-1385: Fill missing descriptions for introspection and fix grammar

Descriptions are empty; add concise text and improve the secret note.

-    "introspection": {
-      "type": "object",
-      "description": "",
+    "introspection": {
+      "type": "object",
+      "description": "Configuration for GraphQL introspection.",
       "additionalProperties": false,
       "properties": {
         "enabled": {
           "type": "boolean",
-          "description": "",
+          "description": "Enable GraphQL introspection.",
           "default": true
         },
         "secret": {
           "type": "string",
-          "description": "A dedicated secret to authenticate introspection requests independently from the regular authentication. Need to passed by introspection queries via the 'Authorization' header. Works only when authentication.ignore_introspection is true.",
+          "description": "Optional secret to authenticate introspection requests independently from regular auth. Must be passed via the 'Authorization' header. Effective only when authentication.ignore_introspection is true.",
           "minLength": 32
         }
       }
     },

Optional (nice-to-have): enforce interaction via an if/then at the root so that when introspection.secret is present, authentication.ignore_introspection must be true.


1851-1855: Fix grammar in ignore_introspection description

Minor copy tweak.

-          "description": "If the value is true, introspection requests not need to be authenticated. The default value is false.",
+          "description": "If true, introspection requests do not need to be authenticated. The default value is false.",
router/core/supervisor_instance.go (2)

73-77: Update warning logic and messaging to the new config path

Use the new flag and reference /introspection/skip_authentication in the message.

Apply this diff:

-	if cfg.Authentication.IgnoreIntrospection && cfg.IntrospectionConfig.Secret == "" {
-		params.Logger.Warn("introspection operations are not authenticated. " +
-			"Consider setting /introspection/secret or set /authentication/ignore_introspection to false. Do not use this in production.")
-	}
+	if cfg.IntrospectionConfig.SkipAuthentication && cfg.IntrospectionConfig.Secret == "" {
+		params.Logger.Warn("introspection operations are not authenticated. " +
+			"Consider setting /introspection/secret or set /introspection/skip_authentication to false. Do not use this in production.")
+	}

78-80: Align second warning with new config path

Reference /introspection/skip_authentication instead of the deprecated field.

Apply this diff:

-	if !cfg.Authentication.IgnoreIntrospection && cfg.IntrospectionConfig.Secret != "" {
-		params.Logger.Warn("/introspection/secret is ignored because /authentication/ignore_introspection is false.")
-	}
+	if !cfg.IntrospectionConfig.SkipAuthentication && cfg.IntrospectionConfig.Secret != "" {
+		params.Logger.Warn("/introspection/secret is ignored because /introspection/skip_authentication is false.")
+	}
router-tests/authentication_test.go (1)

45-52: Reduce duplication: helper for controller setup in tests

Consider a small test helper to build the controller to cut repetition and prevent future drift:

func newAccessControllerForTests(t *testing.T, auths []authentication.Authenticator, required bool, skipIntrospection bool, secret string) *core.AccessController {
	ac, err := core.NewAccessController(core.AccessControllerOptions{
		Authenticators:           auths,
		AuthenticationRequired:   required,
		SkipIntrospectionQueries: skipIntrospection,
		IntrospectionSkipSecret:  secret,
	})
	require.NoError(t, err)
	return ac
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2d3c46a and a792387.

📒 Files selected for processing (7)
  • router-tests/authentication_test.go (68 hunks)
  • router-tests/header_set_test.go (1 hunks)
  • router/core/supervisor_instance.go (2 hunks)
  • router/pkg/config/config.go (3 hunks)
  • router/pkg/config/config.schema.json (2 hunks)
  • router/pkg/config/fixtures/full.yaml (2 hunks)
  • router/pkg/config/testdata/config_full.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • router/pkg/config/testdata/config_full.json
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2025-07-21T15:06:36.664Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2067
File: router/pkg/config/config.schema.json:1637-1644
Timestamp: 2025-07-21T15:06:36.664Z
Learning: In the Cosmo router project, when extending JSON schema validation for security-sensitive fields like JWKS secrets, backwards compatibility is maintained by implementing warnings in the Go code rather than hard validation constraints in the schema. This allows existing configurations to continue working while alerting users to potential security issues.

Applied to files:

  • router/pkg/config/config.schema.json
📚 Learning: 2025-07-21T14:46:34.879Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2067
File: router/pkg/authentication/jwks_token_decoder.go:80-106
Timestamp: 2025-07-21T14:46:34.879Z
Learning: In the Cosmo router project, required field validation for JWKS configuration (Secret, Algorithm, KeyId) is handled at the JSON schema level in config.schema.json rather than through runtime validation in the Go code at router/pkg/authentication/jwks_token_decoder.go.

Applied to files:

  • router/pkg/config/fixtures/full.yaml
📚 Learning: 2025-09-22T11:13:39.415Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/keyfunc/keyfunc_test.go:167-178
Timestamp: 2025-09-22T11:13:39.415Z
Learning: When reviewing forked code from external libraries, gitleaks warnings for hardcoded test tokens/credentials should typically be ignored as they are legitimate test fixtures from the upstream source, not real sensitive data.

Applied to files:

  • router/pkg/config/fixtures/full.yaml
  • router-tests/authentication_test.go
📚 Learning: 2025-09-22T11:13:45.607Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/keyfunc/keyfunc_test.go:142-154
Timestamp: 2025-09-22T11:13:45.607Z
Learning: When reviewing forked code, especially test files with test fixtures like JWT tokens, avoid suggesting modifications to maintain alignment with upstream and preserve the original author's structure. Test fixtures that are clearly marked as such (not real secrets) should generally be left unchanged in forked implementations.

Applied to files:

  • router/pkg/config/fixtures/full.yaml
📚 Learning: 2025-09-17T18:13:31.021Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/jwks_token_decoder.go:176-199
Timestamp: 2025-09-17T18:13:31.021Z
Learning: In router/pkg/authentication/jwks_token_decoder.go, when AllowEmptyAlgorithm is true, the allowedAlgorithms slice is populated by getSupportedAlgorithms() from validation_store.go, ensuring it's never empty and preventing unintended token rejections. The validation store maintains its own internal supported algorithms map that gets returned regardless of input parameters.

Applied to files:

  • router-tests/authentication_test.go
📚 Learning: 2025-09-17T18:13:31.021Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/jwks_token_decoder.go:176-199
Timestamp: 2025-09-17T18:13:31.021Z
Learning: In router/pkg/authentication/jwks_token_decoder.go, when AllowEmptyAlgorithm is true, the allowedAlgorithms slice is populated by getSupportedAlgorithms() from validation_store.go, ensuring it's never empty and preventing unintended token rejections.

Applied to files:

  • router-tests/authentication_test.go
🧬 Code graph analysis (4)
router-tests/header_set_test.go (3)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router-tests/testenv/testenv.go (2)
  • Run (107-124)
  • Config (286-342)
router/core/router.go (1)
  • WithAccessController (1825-1829)
router/core/supervisor_instance.go (2)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (2)
  • WithAccessController (1825-1829)
  • WithIntrospection (1554-1559)
router/pkg/config/config.go (1)
demo/pkg/subgraphs/test1/subgraph/model/models_gen.go (1)
  • Secret (667-669)
router-tests/authentication_test.go (4)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router-tests/testenv/testenv.go (3)
  • Run (107-124)
  • Config (286-342)
  • Environment (1731-1767)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router-tests/utils.go (2)
  • ConfigureAuth (45-57)
  • JwksName (19-19)
🪛 GitHub Actions: Router CI
router-tests/authentication_test.go

[error] 91-91: go vet failed: ./authentication_test.go:91:72: too many arguments in call to core.NewAccessController

🔇 Additional comments (11)
router/pkg/config/fixtures/full.yaml (2)

273-273: New flag placement LGTM

authentication.ignore_introspection defaults are explicit here; fine for a “full” fixture.


277-287: JWKS options extension LGTM

refresh_interval, algorithms, and refresh_unknown_kid match the schema and code. Good sample coverage.

router/pkg/config/config.go (2)

505-507: Expose ignore_introspection on Authentication: LGTM

Field surfaces the new behavior cleanly; no env tag avoids precedence confusion.


996-999: IntrospectionConfiguration addition: LGTM

YAML/env tags are consistent and align with the schema.

router/pkg/config/config.schema.json (2)

1360-1361: Clear deprecation message for playground_enabled: LGTM

Good guidance toward playground.enabled.


1365-1368: introspection_enabled deprecation: LGTM

Defaults and message are clear.

router/core/supervisor_instance.go (1)

59-71: Wire introspection.skip_authentication (keep back‑compat) and initialize AccessController when appropriate

  • Replace usage of cfg.Authentication.IgnoreIntrospection with cfg.IntrospectionConfig.SkipAuthentication OR them for back‑compat; set SkipIntrospectionQueries accordingly (router/core/supervisor_instance.go:59-71).
  • Instantiate AccessController when any of these are true: cfg.Authorization.RequireAuthentication || cfg.IntrospectionConfig.SkipAuthentication || cfg.IntrospectionConfig.Secret != "" || len(authenticators) > 0 (same file).
  • Adjust the warning logic that currently compares cfg.Authentication.IgnoreIntrospection and cfg.IntrospectionConfig.Secret (router/core/supervisor_instance.go:73-80) to account for the new SkipAuthentication flag.
  • Note: repository search shows no usages of IntrospectionConfig.SkipAuthentication — confirm this config field exists (or add it) before applying; current code only references cfg.Authentication.IgnoreIntrospection.
router-tests/header_set_test.go (1)

278-285: Options-based AccessController wiring looks correct

Constructing via AccessControllerOptions and injecting with WithAccessController(accessController) is aligned with the new API and asserts errors properly.

Also applies to: 292-293

router-tests/authentication_test.go (3)

29-36: Good test constants for introspection coverage

The added constants make the new cases clear and reusable.


45-52: Nice migration to options-based NewAccessController across tests

Consistent construction with error checks and explicit SkipIntrospectionQueries/IntrospectionSkipSecret improves clarity.

Also applies to: 401-407, 433-440, 468-474, 493-500, 527-533, 562-568, 596-602, 631-637, 670-676, 707-713, 740-746, 771-777, 806-812, 841-847, 878-884, 905-911, 932-939, 961-967, 993-1001, 1029-1036, 1065-1071, 1099-1106, 1160-1167, 1357-1364, 1423-1430, 1474-1481, 1521-1528, 1571-1576, 1663-1670, 1802-1809, 1838-1845, 1969-1976, 2061-2068, 2091-2098, 2121-2128, 2155-2161, 2189-2195, 2278-2284, 2315-2321, 2352-2358, 2389-2395, 2426-2432, 2463-2469, 2504-2510, 2541-2547, 2578-2584, 2619-2625, 2660-2666, 2697-2703, 2734-2740, 2773-2779, 2834-2840, 2880-2886, 2927-2933, 2979-2985, 3024-3030, 3085-3091, 3130-3136, 3186-3192, 3230-3236, 3284-3290, 3331-3337


3360-3650: Introspection auth-bypass tests cover key paths; confirm Authorization format

Coverage looks solid: POST/GET detection, bypass with/without bearer JWT, and secret-gated mode. One verification: should the secret be accepted both as "Authorization: " and "Authorization: Bearer "? If only one is supported, add/adjust a test to lock the contract.

Comment thread router-tests/authentication_test.go
Comment thread router/core/supervisor_instance.go
Comment thread router/pkg/config/config.go
@dkorittki dkorittki force-pushed the dominik/eng-7980-allow-to-exclude-introspection-endpoint-from-auth branch from a792387 to 77a2517 Compare September 23, 2025 15:55
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
router-tests/authentication_test.go (1)

44-56: Reduce test duplication: extract AccessController builder helper

The options-based AccessController construction repeats throughout the file. Consider a small test helper to DRY it up.

Example helper (place in this package’s test utils):

func newAccessControllerForTests(t *testing.T, authenticators []authentication.Authenticator, requireAuth, skipIntrospection bool, secret string) *core.AccessController {
	t.Helper()
	ac, err := core.NewAccessController(core.AccessControllerOptions{
		Authenticators:           authenticators,
		AuthenticationRequired:   requireAuth,
		SkipIntrospectionQueries: skipIntrospection,
		IntrospectionSkipSecret:  secret,
	})
	require.NoError(t, err)
	return ac
}

Then replace repeated blocks with:

accessController := newAccessControllerForTests(t, authenticators, true, false, "")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a792387 and 77a2517.

📒 Files selected for processing (7)
  • router-tests/authentication_test.go (74 hunks)
  • router-tests/header_set_test.go (1 hunks)
  • router/core/supervisor_instance.go (2 hunks)
  • router/pkg/config/config.go (3 hunks)
  • router/pkg/config/config.schema.json (2 hunks)
  • router/pkg/config/fixtures/full.yaml (2 hunks)
  • router/pkg/config/testdata/config_full.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • router-tests/header_set_test.go
  • router/pkg/config/testdata/config_full.json
  • router/pkg/config/fixtures/full.yaml
  • router/pkg/config/config.go
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-09-22T11:13:39.415Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/keyfunc/keyfunc_test.go:167-178
Timestamp: 2025-09-22T11:13:39.415Z
Learning: When reviewing forked code from external libraries, gitleaks warnings for hardcoded test tokens/credentials should typically be ignored as they are legitimate test fixtures from the upstream source, not real sensitive data.

Applied to files:

  • router-tests/authentication_test.go
📚 Learning: 2025-09-17T18:13:31.021Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/jwks_token_decoder.go:176-199
Timestamp: 2025-09-17T18:13:31.021Z
Learning: In router/pkg/authentication/jwks_token_decoder.go, when AllowEmptyAlgorithm is true, the allowedAlgorithms slice is populated by getSupportedAlgorithms() from validation_store.go, ensuring it's never empty and preventing unintended token rejections. The validation store maintains its own internal supported algorithms map that gets returned regardless of input parameters.

Applied to files:

  • router-tests/authentication_test.go
📚 Learning: 2025-09-17T18:13:31.021Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2224
File: router/pkg/authentication/jwks_token_decoder.go:176-199
Timestamp: 2025-09-17T18:13:31.021Z
Learning: In router/pkg/authentication/jwks_token_decoder.go, when AllowEmptyAlgorithm is true, the allowedAlgorithms slice is populated by getSupportedAlgorithms() from validation_store.go, ensuring it's never empty and preventing unintended token rejections.

Applied to files:

  • router-tests/authentication_test.go
📚 Learning: 2025-07-21T15:06:36.664Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2067
File: router/pkg/config/config.schema.json:1637-1644
Timestamp: 2025-07-21T15:06:36.664Z
Learning: In the Cosmo router project, when extending JSON schema validation for security-sensitive fields like JWKS secrets, backwards compatibility is maintained by implementing warnings in the Go code rather than hard validation constraints in the schema. This allows existing configurations to continue working while alerting users to potential security issues.

Applied to files:

  • router/pkg/config/config.schema.json
🧬 Code graph analysis (2)
router/core/supervisor_instance.go (2)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (2)
  • WithAccessController (1825-1829)
  • WithIntrospection (1554-1559)
router-tests/authentication_test.go (3)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router-tests/utils.go (2)
  • ConfigureAuth (45-57)
  • JwksName (19-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: build-router
  • GitHub Check: build_push_image
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: integration_test (./events)
  • GitHub Check: build_test
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: image_scan
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
🔇 Additional comments (5)
router/pkg/config/config.schema.json (2)

1360-1360: LGTM: clearer playground deprecation message.


1365-1368: LGTM: deprecate introspection_enabled with migration hint.

router-tests/authentication_test.go (2)

3408-3698: Introspection auth-bypass tests look solid

Good coverage across POST/GET, valid/invalid bearer, and token-required scenarios.


3584-3596: Confirm Authorization header scheme for introspection token

Tests send the raw secret (no "Bearer " prefix). Ensure AccessController and docs expect this exact scheme.

router/core/supervisor_instance.go (1)

177-177: Use introspection.enabled (fallback to deprecated flag)

Enable introspection if either the new or deprecated flag is true.

-		WithIntrospection(config.IntrospectionEnabled, config.IntrospectionConfig),
+		WithIntrospection(config.IntrospectionConfig.Enabled || config.IntrospectionEnabled, config.IntrospectionConfig),

Comment thread router/core/supervisor_instance.go
Comment thread router/core/supervisor_instance.go
Comment thread router/pkg/config/config.schema.json
Comment thread router/pkg/config/config.schema.json
@dkorittki dkorittki requested a review from StarpTech September 26, 2025 08:24
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
router/pkg/config/config.go (1)

506-508: Unify introspection auth config; avoid split/precedence pitfalls

You’re introducing both Authentication.IgnoreIntrospection and a new Introspection section. This can create ambiguous precedence (e.g., ignore_introspection=true vs. requiring a secret/token under introspection). Prefer a single source of truth under Introspection to steer auth behavior and mark ignore_introspection as deprecated, or wire clear precedence in post-processing. Also, the PR narrative uses “token”, while the struct uses “secret” — that’s a doc/schema drift risk.

Recommended:

  • Consolidate knobs under Introspection (e.g., authentication_mode: full|token|skip and token).
  • Keep current fields for compatibility but document precedence and deprecations.

If you keep both for now, please confirm schema/docs reflect the final shape and precedence.

Minimal schema-alignment patch (add token alias and optional mode without breaking existing secret/env):

 type IntrospectionConfiguration struct {
-    Enabled bool   `yaml:"enabled" envDefault:"true" env:"INTROSPECTION_ENABLED"`
-    Secret  string `yaml:"secret" env:"INTROSPECTION_SECRET"`
+    Enabled            bool   `yaml:"enabled" envDefault:"true" env:"INTROSPECTION_ENABLED"`
+    // Token preferred in docs; keep Secret for back-compat with env while we transition.
+    Token              string `yaml:"token,omitempty" env:"INTROSPECTION_TOKEN"`
+    Secret             string `yaml:"secret,omitempty" env:"INTROSPECTION_SECRET"` // deprecated
+    AuthenticationMode string `yaml:"authentication_mode,omitempty" env:"INTROSPECTION_AUTHENTICATION_MODE"` // allowed: full|token|skip
 }

Optionally mark the new Authentication.IgnoreIntrospection as deprecated in favor of introspection.authentication_mode=skip, or move it under Introspection to avoid scattering related knobs.

Also applies to: 997-1000, 1028-1029

router-tests/websocket_test.go (1)

139-146: Adoption of AccessControllerOptions is correct; reduce duplication with a tiny helper

The per-test construction/injection of AccessController is repetitive but otherwise solid. Extract a helper to cut noise and make intent clearer.

Example helper for this file:

func newAccessControllerForTests(t *testing.T, auths []authentication.Authenticator, required bool) *core.AccessController {
  t.Helper()
  ac, err := core.NewAccessController(core.AccessControllerOptions{
    Authenticators:         auths,
    AuthenticationRequired: required,
    // Defaults for introspection behavior; override per test if needed.
  })
  require.NoError(t, err)
  return ac
}

Then replace blocks like:

accessController, err := core.NewAccessController(core.AccessControllerOptions{ ... })
require.NoError(t, err)
...
core.WithAccessController(accessController),

with:

core.WithAccessController(newAccessControllerForTests(t, authenticators, false)),

This trims several hundred repeated lines without changing behavior. Based on learnings.

Also applies to: 149-149, 196-203, 206-206, 252-259, 264-264, 318-325, 330-330, 384-390, 399-399, 453-459, 466-466, 509-515, 522-522, 916-923, 945-945

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a25f100 and bea860b.

📒 Files selected for processing (5)
  • router-tests/websocket_test.go (10 hunks)
  • router/pkg/config/config.go (3 hunks)
  • router/pkg/config/config.schema.json (2 hunks)
  • router/pkg/config/testdata/config_defaults.json (2 hunks)
  • router/pkg/config/testdata/config_full.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • router/pkg/config/testdata/config_defaults.json
  • router/pkg/config/testdata/config_full.json
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-23T16:27:54.358Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/core/supervisor_instance.go:59-71
Timestamp: 2025-09-23T16:27:54.358Z
Learning: In the router codebase, AccessController creation follows a nil pattern where accessController == nil signals that no authentication should be performed. Other parts of the code (like the prehandler) check for accessController == nil to determine whether to skip authentication entirely. Always creating an AccessController would break this pattern and cause authentication to be attempted even when no authenticators are configured.

Applied to files:

  • router-tests/websocket_test.go
📚 Learning: 2025-07-21T15:06:36.664Z
Learnt from: SkArchon
PR: wundergraph/cosmo#2067
File: router/pkg/config/config.schema.json:1637-1644
Timestamp: 2025-07-21T15:06:36.664Z
Learning: In the Cosmo router project, when extending JSON schema validation for security-sensitive fields like JWKS secrets, backwards compatibility is maintained by implementing warnings in the Go code rather than hard validation constraints in the schema. This allows existing configurations to continue working while alerting users to potential security issues.

Applied to files:

  • router/pkg/config/config.schema.json
🧬 Code graph analysis (1)
router-tests/websocket_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: build-router
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: build_push_image
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: integration_test (./events)
  • GitHub Check: image_scan
  • GitHub Check: build_test
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
  • GitHub Check: build_test
🔇 Additional comments (4)
router/pkg/config/config.schema.json (4)

1360-1360: Deprecation message for playground_enabled: LGTM.

Message clearly points to playground.enabled.


1365-1368: introspection_enabled deprecation path: LGTM.

Keeps default and directs users to introspection.enabled.


1369-1384: Fill descriptions, fix secret wording, and avoid hard minLength in schema (warn in Go instead).

  • Add a meaningful description for introspection.
  • Use dot-path in secret description and note intended local/dev use.
  • Remove minLength: 32 here and validate length with a warning in Go to preserve flexibility. Based on learnings.

Apply:

 "introspection": {
   "type": "object",
-  "description": "",
+  "description": "Configuration for GraphQL introspection. Not recommended for production; see documentation.",
   "additionalProperties": false,
   "properties": {
     "enabled": {
       "type": "boolean",
       "description": "Enable the GraphQL introspection. The GraphQL introspection allows you to query the schema of the GraphQL API. The default value is true. If the value is false, the GraphQL introspection is disabled. In production, it is recommended to disable the introspection.",
       "default": true
     },
     "secret": {
       "type": "string",
-      "description": "A dedicated secret to protect introspection when skipping standard authentication. Needs to be passed via the 'Authorization' header. Effective only when /authentication/ignore_introspection is true.",
-      "minLength": 32
+      "description": "A dedicated secret to protect introspection when skipping standard authentication. Needs to be passed via the 'Authorization' header. Effective only when authentication.ignore_introspection is true. Intended for local/dev use."
     }
   }
 }

Optionally, enforce the interplay in Go validation (emit warning/errors on misuse) instead of schema constraints to maintain backward compatibility. Based on learnings.


1851-1855: Grammar fix for ignore_introspection description.

Use “do not need to be authenticated.”

 "ignore_introspection": {
   "type": "boolean",
-  "description": "If the value is true, introspection requests not need to be authenticated. The default value is false.",
+  "description": "If true, introspection requests do not need to be authenticated. The default value is false.",
   "default": false
 }

Comment thread router/pkg/config/config.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bea860b and 04abf5a.

📒 Files selected for processing (1)
  • router/core/supervisor_instance.go (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-29T10:28:07.088Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/pkg/config/config.go:1028-1029
Timestamp: 2025-09-29T10:28:07.088Z
Learning: The deprecation strategy for IntrospectionEnabled field in router/pkg/config/config.go is to first mark it as deprecated, then migrate all call sites to use IntrospectionConfig.Enabled, and finally remove the deprecated field. The envDefault tag should be kept during the deprecation period for backward compatibility.

Applied to files:

  • router/core/supervisor_instance.go
📚 Learning: 2025-09-23T16:27:54.358Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/core/supervisor_instance.go:59-71
Timestamp: 2025-09-23T16:27:54.358Z
Learning: In the router codebase, AccessController creation follows a nil pattern where accessController == nil signals that no authentication should be performed. Other parts of the code (like the prehandler) check for accessController == nil to determine whether to skip authentication entirely. Always creating an AccessController would break this pattern and cause authentication to be attempted even when no authenticators are configured.

Applied to files:

  • router/core/supervisor_instance.go
🧬 Code graph analysis (1)
router/core/supervisor_instance.go (3)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/pkg/authentication/authentication.go (1)
  • Authentication (27-40)
router/core/router.go (2)
  • WithAccessController (1825-1829)
  • WithIntrospection (1554-1559)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: build-router
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: image_scan
  • GitHub Check: build_push_image
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: integration_test (./events)
  • GitHub Check: Analyze (go)
  • GitHub Check: build_test
🔇 Additional comments (2)
router/core/supervisor_instance.go (2)

73-80: Remove or revise references to non-existent IntrospectionConfig fields
The IntrospectionConfiguration struct only defines Enabled and Secret; there are no SkipAuthentication or Token fields to reference in these warnings.

Likely an incorrect or invalid review comment.


177-177: Honor both IntrospectionConfig.Enabled and deprecated IntrospectionEnabled when invoking WithIntrospection

-       WithIntrospection(config.IntrospectionEnabled, config.IntrospectionConfig),
+       WithIntrospection(config.IntrospectionConfig.Enabled || config.IntrospectionEnabled, config.IntrospectionConfig),

Comment thread router/core/supervisor_instance.go
Comment thread router/core/graphql_prehandler.go Outdated
Comment thread router/core/supervisor_instance.go Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
router-tests/authentication_test.go (1)

3394-3394: Complete the AccessController API migration.

These calls still use the deprecated positional constructor core.NewAccessController(authenticators, bool) instead of the new options-based API used throughout the rest of the file. For consistency and to follow the migration pattern, update these to use core.AccessControllerOptions.

Apply this pattern (example for line 3394):

-			core.WithAccessController(core.NewAccessController(authenticators, true)),
+		accessController, err := core.NewAccessController(core.AccessControllerOptions{
+			Authenticators:           authenticators,
+			AuthenticationRequired:   true,
+			SkipIntrospectionQueries: false,
+			IntrospectionSkipSecret:  "",
+		})
+		require.NoError(t, err)
+
+		testenv.Run(t, &testenv.Config{
+			RouterOptions: []core.Option{
+				core.WithAccessController(accessController),
+			},

Repeat this pattern for lines 3440, 3525, 3569, 3604, and 3656.

Also applies to: 3440-3440, 3525-3525, 3569-3569, 3604-3604, 3656-3656

♻️ Duplicate comments (7)
router/pkg/config/config.schema.json (1)

1860-1863: Fix grammar in ignore_introspection description.

The sentence should read “introspection requests do not need to be authenticated.” Please adjust the wording.

-      "description": "If the value is true, introspection requests not need to be authenticated. The default value is false.",
+      "description": "If the value is true, introspection requests do not need to be authenticated. The default value is false.",
router-tests/telemetry/telemetry_test.go (6)

9106-9112: Same refactor applies here (omit zero-values / optional helper)

Also applies to: 9125-9125


9161-9168: Same refactor applies here (omit zero-values / optional helper)

Also applies to: 9180-9180


9243-9249: Same refactor applies here (omit zero-values / optional helper)

Also applies to: 9272-9272


9326-9332: Same refactor applies here (omit zero-values / optional helper)

Also applies to: 9347-9347


9392-9398: Same refactor applies here (omit zero-values / optional helper)

Also applies to: 9411-9411


9601-9606: Same refactor applies here (omit zero-values / optional helper)

Also applies to: 9625-9625

🧹 Nitpick comments (3)
router/core/graphql_prehandler.go (1)

646-675: Consider simplifying the nested conditionals.

The validation logic is correct but could be more readable with early returns or a helper function.

Optional refactor for improved readability:

 	if h.accessController != nil {
-		// Based on the authentication result, the introspection config,
-		// and wether this is an introspection query,
-		// we decide here if we need to abort the request or not.
 		isIntrospection, err := operationKit.isIntrospectionQuery()
 		if err != nil {
 			requestContext.logger.Error("failed to check if operation is introspection, treat it like non-introspection operation", zap.Error(err))
 			isIntrospection = false
 		}
 
-		// non-introspection queries are only allowed when authenticated via normal authentication
-		if !isIntrospection && httpOperation.authenticationPass != authenticationPassNormal {
+		// Determine if authentication is sufficient for this operation type
+		authAllowed := false
+		if !isIntrospection {
+			// Non-introspection requires normal authentication
+			authAllowed = (httpOperation.authenticationPass == authenticationPassNormal)
+		} else {
+			// Introspection allows normal auth, secret auth, or skip
+			authAllowed = (httpOperation.authenticationPass == authenticationPassNormal ||
+				httpOperation.authenticationPass == authenticationPassIntrospectionSecret ||
+				httpOperation.authenticationPass == authenticationPassSkip)
+		}
+
+		if !authAllowed {
 			return &httpGraphqlError{
 				message:    "unauthorized",
 				statusCode: http.StatusUnauthorized,
 			}
 		}
-
-		// introspection queries are only allowed when authenticated normally or via dedicated token, or when auth skip is enabled
-		// note: httpOperation.authMethod is only set when authentication is successful and the config allows such authentication.
-		if isIntrospection &&
-			httpOperation.authenticationPass != authenticationPassNormal &&
-			httpOperation.authenticationPass != authenticationPassIntrospectionSecret &&
-			httpOperation.authenticationPass != authenticationPassSkip {
-			return &httpGraphqlError{
-				message:    "unauthorized",
-				statusCode: http.StatusUnauthorized,
-			}
-		}
 	}
router/pkg/config/config.schema.json (1)

1374-1388: Document the introspection block.

The new introspection object currently has an empty description. Please add a short explanation (e.g., that it configures GraphQL introspection and is not recommended for production) so the schema docs stay usable.

router-tests/telemetry/telemetry_test.go (1)

9047-9054: Good adoption of NewAccessController and WithAccessController; remove redundant zero‑values and consider a small helper

  • The usage is correct. You can drop explicit zero‑value options to reduce noise (bool false, empty string).
  • Given the repetition across this file, consider a tiny test helper to construct the controller once.

Suggested minimal change here:

-accessController, err := core.NewAccessController(core.AccessControllerOptions{
-    Authenticators:           authenticators,
-    AuthenticationRequired:   false,
-    SkipIntrospectionQueries: false,
-    IntrospectionSkipSecret:  "",
-})
+accessController, err := core.NewAccessController(core.AccessControllerOptions{
+    Authenticators: authenticators,
+})
 require.NoError(t, err)

Optionally, introduce a helper and use it at call sites:

// in this package (test file), for reuse
func newTestAccessController(t *testing.T, authenticators []authentication.Authenticator) *core.AccessController {
  ac, err := core.NewAccessController(core.AccessControllerOptions{
    Authenticators: authenticators,
    // AuthenticationRequired false by default; add fields here only if a test needs them.
  })
  require.NoError(t, err)
  return ac
}

Then:

-accessController, err := core.NewAccessController(core.AccessControllerOptions{ ... })
-require.NoError(t, err)
+accessController := newTestAccessController(t, authenticators)

Also applies to: 9068-9068

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 04abf5a and cafa760.

📒 Files selected for processing (13)
  • router-tests/authentication_test.go (74 hunks)
  • router-tests/batch_test.go (2 hunks)
  • router-tests/block_operations_test.go (3 hunks)
  • router-tests/ratelimit_test.go (1 hunks)
  • router-tests/telemetry/telemetry_test.go (14 hunks)
  • router-tests/testenv/testenv.go (1 hunks)
  • router/core/graphql_prehandler.go (6 hunks)
  • router/core/router.go (2 hunks)
  • router/core/supervisor_instance.go (2 hunks)
  • router/pkg/config/config.go (3 hunks)
  • router/pkg/config/config.schema.json (2 hunks)
  • router/pkg/config/testdata/config_defaults.json (2 hunks)
  • router/pkg/config/testdata/config_full.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • router-tests/batch_test.go
  • router-tests/testenv/testenv.go
  • router/pkg/config/testdata/config_full.json
  • router-tests/block_operations_test.go
  • router/pkg/config/testdata/config_defaults.json
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-29T10:28:07.122Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/pkg/config/config.go:1028-1029
Timestamp: 2025-09-29T10:28:07.122Z
Learning: The deprecation strategy for IntrospectionEnabled field in router/pkg/config/config.go is to first mark it as deprecated, then migrate all call sites to use IntrospectionConfig.Enabled, and finally remove the deprecated field. The envDefault tag should be kept during the deprecation period for backward compatibility.

Applied to files:

  • router/core/supervisor_instance.go
  • router/pkg/config/config.schema.json
  • router/pkg/config/config.go
  • router/core/router.go
📚 Learning: 2025-09-23T16:27:54.358Z
Learnt from: dkorittki
PR: wundergraph/cosmo#2192
File: router/core/supervisor_instance.go:59-71
Timestamp: 2025-09-23T16:27:54.358Z
Learning: In the router codebase, AccessController creation follows a nil pattern where accessController == nil signals that no authentication should be performed. Other parts of the code (like the prehandler) check for accessController == nil to determine whether to skip authentication entirely. Always creating an AccessController would break this pattern and cause authentication to be attempted even when no authenticators are configured.

Applied to files:

  • router/core/supervisor_instance.go
🧬 Code graph analysis (6)
router-tests/ratelimit_test.go (3)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router-tests/testenv/testenv.go (2)
  • Run (107-124)
  • Config (286-343)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router/core/supervisor_instance.go (2)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (2)
  • WithAccessController (1825-1829)
  • WithIntrospection (1554-1559)
router-tests/authentication_test.go (4)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router-tests/testenv/testenv.go (4)
  • Run (107-124)
  • Config (286-343)
  • Environment (1733-1769)
  • GraphQLRequest (1909-1917)
router/core/router.go (2)
  • Option (172-172)
  • WithAccessController (1825-1829)
router-tests/utils.go (2)
  • ConfigureAuth (45-57)
  • JwksName (19-19)
router-tests/telemetry/telemetry_test.go (2)
router/core/access_controller.go (2)
  • NewAccessController (37-44)
  • AccessControllerOptions (20-25)
router/core/router.go (1)
  • WithAccessController (1825-1829)
router/core/graphql_prehandler.go (2)
router/internal/expr/expr.go (3)
  • Request (66-75)
  • LoadAuth (189-201)
  • Context (35-39)
router/pkg/trace/utils.go (1)
  • AttachErrToSpan (75-81)
router/core/router.go (1)
router/pkg/config/config.go (1)
  • IntrospectionConfiguration (999-1002)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: build-router
  • GitHub Check: build_test
  • GitHub Check: image_scan
  • GitHub Check: build_push_image
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: integration_test (./events)
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: build_test
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
🔇 Additional comments (15)
router/core/graphql_prehandler.go (3)

111-129: LGTM: Clean authentication pass tracking.

The authenticationPass enum and its integration into httpOperation provide a clear way to track the authentication outcome through the request lifecycle. The four states (none, normal, introspection secret, skip) cover all the scenarios introduced by the introspection bypass feature.


341-396: Well-designed two-stage authentication approach.

The early authentication (before parsing) is necessary to determine the authentication pass type, while the actual enforcement is deferred until after parsing when we know the operation type. This design correctly handles:

  1. Early rejection (lines 357-364): When auth fails and introspection skip is disabled
  2. Secret validation (lines 366-375): Constant-time comparison when introspection secret is configured
  3. Pass tracking (lines 372, 374, 379): Stores the authentication outcome for later validation

The separation of authentication attempt and authorization decision is the right approach for this use case.


1142-1154: Good refactoring: consolidated error handling.

The handleAuthenticationFailure helper eliminates code duplication and ensures consistent error handling across authentication failure paths.

router-tests/ratelimit_test.go (1)

273-283: LGTM: Correct migration to new AccessController API.

The test correctly adopts the options-based construction pattern with proper error handling and injection via WithAccessController.

router/core/router.go (2)

225-232: LGTM: Proper deprecation handling with correct config path references.

The introspection config deprecation correctly:

  • Uses dot notation for config paths (addressing past review feedback)
  • Synchronizes values bidirectionally to ensure consistency
  • Emits warnings only when the deprecated field is explicitly set to false

1554-1558: LGTM: WithIntrospection signature updated correctly.

The function now accepts both the enable flag and the introspection config struct, properly storing both values in the router.

router/core/supervisor_instance.go (3)

59-71: LGTM: Correct AccessController construction maintaining nil pattern.

The code correctly:

  • Maintains the nil AccessController pattern when no authenticators are configured (as per retrieved learnings)
  • Uses the new options-based API with proper error handling
  • Wires the introspection skip flag and secret from the correct config locations

Based on learnings


73-80: LGTM: Clear warning messages with correct config references.

The warnings properly:

  • Use dot notation for config paths (addressing past review feedback)
  • Guide users to the correct configuration parameters
  • Cover both misconfiguration scenarios (skip without secret, secret without skip)

177-177: LGTM: WithIntrospection call updated correctly.

The call properly passes both the legacy enabled flag and the new introspection config struct, matching the updated signature in router/core/router.go.

router/pkg/config/config.go (3)

508-510: LGTM: Authentication configuration extended for introspection control.

The new IgnoreIntrospection field enables fine-grained control over introspection authentication behavior, with a safe default of false (authentication required).


999-1002: LGTM: Clean introspection configuration structure.

The new IntrospectionConfiguration type provides a structured way to configure introspection with optional secret-based authentication. The default of enabled: true maintains backward compatibility.


1030-1031: LGTM: Deprecation handled correctly.

The deprecated IntrospectionEnabled field retains its envDefault:"true" for backward compatibility while the new IntrospectionConfig field provides structured configuration. The env var collision has been properly resolved (deprecated field no longer reads from env).

Based on learnings.

router-tests/authentication_test.go (3)

31-38: LGTM: Well-defined test constants.

The new introspection test constants follow existing naming conventions and provide clear, simple test data for verifying introspection authentication behavior.


47-57: LGTM: Clean migration to options-based API.

The AccessController construction has been correctly migrated to the new options-based API with proper error handling. The explicit field initialization makes the configuration clear and maintainable.


3679-3969: LGTM: Comprehensive introspection authentication test coverage.

The new test suite thoroughly validates introspection authentication behavior across multiple scenarios:

  • Full authentication requirement enforcement
  • Authentication skip for introspection queries
  • HTTP GET and POST method handling
  • Token validation precedence over skip
  • Secret-based introspection access
  • Isolation between introspection and normal queries

The test cases are well-structured, clearly named, and cover both positive and negative paths.

Previous merge with main overwrote some code changes from this commit.
@dkorittki dkorittki requested a review from StarpTech October 8, 2025 14:08
@github-actions
Copy link
Copy Markdown

This PR was marked stale due to lack of activity. It will be closed in 14 days.

@github-actions github-actions Bot added the Stale label Oct 23, 2025
@dkorittki dkorittki removed the Stale label Oct 24, 2025
@dkorittki dkorittki requested review from endigma and removed request for endigma October 27, 2025 08:28
Copy link
Copy Markdown
Contributor

@StarpTech StarpTech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Copy Markdown
Member

@endigma endigma left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lgtm

@dkorittki dkorittki merged commit d6a443e into main Oct 28, 2025
37 of 38 checks passed
@dkorittki dkorittki deleted the dominik/eng-7980-allow-to-exclude-introspection-endpoint-from-auth branch October 28, 2025 13:35
@coderabbitai coderabbitai Bot mentioned this pull request Apr 1, 2026
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants